Change Hedera NFT metadata after minting - ipfs

Is there a way to change a Hedera NFT metadata after it has been minted?
My goal is to implement similar NFT minting flow as is usually used in other NFT projects, which is to first have the prereveal metadata and on the day of reveal change it to the actual one.

The NFT metadata field on the ledger is immutable. There is a community proposal on dynamic NFTs which may interest you.
There are other, perhaps "hacky", ways to change the metadata of your NFT (changing the contents of the URI itself), but that may introduce some trust concerns for users.
One could burn and re-mint NFTs, assuming your tokenId (the NFT collection) has a supply key that enables mint/burn operations. Note that that would change the serial number of the NFT.
In case burning is a viable option for you, here's some code to do that:
let tokenBurnTx = await new TokenBurnTransaction()
.setTokenId(tokenId)
.setSerials([nftSerial])
.freezeWith(client)
.sign(supplyKey);
let tokenBurnSubmit = await tokenBurnTx.execute(client);
let tokenBurnRx = await tokenBurnSubmit.getReceipt(client);
console.log(`\nBurn NFT with serial ${nftSerial}: ${tokenBurnRx.status} \n`);

Related

how to actually make an auction functionality into my daap?

I've been trying to make an NFT marketplace with the functionality of auctioning an item. But I don't know how to achieve this via signing transaction.
I have tried to use almost every method of signing from web3.js, but it requires the private key of the user.
However there's the function web3.eth.signTransaction which doesn't require any private key to sign the transaction, but it gives an error on the console. saying : Error: The method 'eth_signTransaction' does not exist / is not available.
Can someone give me an overview of how this signing and sending transaction can be done implementing the functionality of auctioning an nft like nft marketplaces: opensea or foundation.
From the docs:
Signs a transaction. This account needs to be unlocked.
It doesn't require the private key, but it requires the account (that is used for signing the transaction) to be unlocked on the node. Which means the node needs to hold the private key to unlock the account.
It's usually allowed on local nodes such as Ganache or private nodes.
And public nodes such as Infura usually disable this functionality (hence the error message "eth_signTransaction is not available") since they don't store your private keys.
You can ask the user to sign the transaction using their wallet. For example using MetaMask (or any other wallet implementing the Ethereum provider API):
const transactionParameters = {
from: ethereum.selectedAddress, // must match user's active address
to: 'your address'
};
await ethereum.request({
method: 'eth_sendTransaction',
params: [transactionParameters],
});

Solidity - Add Token Logo

Glad to see blockchain development support on Stack Overflow as resources as very scarce nowadays.
I'm a new kid trying to learn this ecosystem.
How can I add an image logo to a token that I've already created and deployed on remix.ethereum.org?
Should I have done this before deploying it?
Newbie question: Once deployed the same code can never modified?
I'm currently interacting with the token on BSC - seems that all BSC tokens are created as a fork of Solidity and the ETH ERC20 paradigm. (?)
This is my code
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract Foobar is ERC20 {
constructor(uint256 initialSupply) public ERC20("Foobar", "FOO") {
_mint(msg.sender, initialSupply);
}
}
Short answer: No, once you deploy a contract to the mainnet, you can't modify nor delete it, it'll be in the blockchain forever (unless you're using a testnet or a private blockchain network to test the contract).
Long answer:
Once a contract is deployed, it can never be modified nor deleted, the only thing you can modify is it's storage (variables that the contract uses) by calling it's defined functions, but you can't modify the logic behind it. If you messed up, you'll need to fix your contract, and re-deploy.
Take in mind that heavy tests and thoughtful inspections are advised before you deploy a contract to the mainnet and set an app into production (and even more if you'r contract will handle sensitive values), mainly because even if you screw up and re-deploy, if you had said contract work in production, its extremly difficult to fix.
For example: You make you'r own tiny bank, the contract recives eth, and it stores it a variable a mapping of addresses with a variable that keeps a count of how much eth from the total eth that the contract is holding is for each user.
contract Bank {
// mapping of address with current money value.
mapping (address user => uint money) balance;
constructor(){}
function withdraw(uint memory money) public {
// Require money parameter is not empty.
require(money != 0, "Can't withdraw 0 eth");
// Big issue here, if we send the money, and then update the balance,
// the user will be able to withdraw money even if hi's balance turns
// to 0 if he spams the withdraw function before he runs out of money.
// The good way would be the other way around, first update balance, and then send.
// Check if the user has enough money.
if (balance[msg.sender].money >= money) {
// Send money
address(msg.sender).transfer(money);
// Update balance.
balance[msg.sender].money -= money;
}
}
...
}
Now this has a critical issue, if someone withdraws money twice very fast, it skips a check iteration that checks if the user has enough money in it's balance to withdraw.
Now to fix this, you'll need to quickly withdraw all the money that the contract has and it's mapping(address user => uint money) ... mapping data, fix and re-deploy the contract, manually send all the money to the new contract, and also set the previous data that it had, and if that wasn't enough you'll need to change you'r front-end app to connect with the new contract.
I know its a long example, but when you start coding contracts from 0, you have to understand that testing and revising the contract is a must.
Once a contract is deployed, it cannot be modified nor deleted, it's there forever, alteast in the mainned, that's why you use private blockchains such as Ganache, or use a public testnet (Ropsten, Kovan, Rinkeby, Goerli).
Also about the logo, most tokens don't have their "logo" in their contract ( unless you're making a NFT [ ERC721 ] ), yet, if you still want to add a logo that anyone can access from your contract, i'd suggest to make a state variable that holds its value (string mainly).
The value can be a IPFS hash (IPFS is a decentralized file system that allows you to upload files of any kind, it will return a hash once it's uploaded, and you can access you'r file via https://HASHTOKEN.ipfs.infura-ipfs.io/, for example:
https://bafybeibctnxu7zpatp3caj2gevofs2oirdvdyo6yulxk2hfyaewxib3pj4.ipfs.infura-ipfs.io/
soo in you'r case, you can upload the logo there, grab the hash, and store it in you'r contract, then in your frontend app you'll only need to add the hash to the url.
A second way of adding you'r logo would be to turn you'r image into base64 and paste the whole thing into you'r contract, that way you have literally the image in the contract, yet, i don't recommend this last solution since base64 strings can get very large depending on how heavy is the file, and the heavier you'r contract is, the more gas it will use when you deploy it, and more expensive for the users when they try to use it.
Yet, if what you mean is to add a logo on sites such as BscScan, you can find a guide here.

NFT - what is actually stored on the block chain to represent the digital asset?

According to Wikipedia's entry on NFT the minting process "creates a copy of the file recorded on the digital ledger as an NFT". Is that literally true of Ethereum based NFT for example? For some reason I was under the impression that what is actually stored inside the blockchain is the cryptographic hash of the underlying digital asset, and possibly a reference to the file's location, not the actual file itself. I guess it's easy enough to store the whole file when it is a jpg, or a 30 second video clip, but if you wanted to represent say "The Godfather" as an NFT, that would really bloat the blockchain if the entire film in 4K (about 11Gb?) had to be saved in the block.
It is in fact hash of the image file, URL of an off-chain resource, or sometimes just a simple ID with no other data.
Take this random NFT token for example. The contract address is 0xd0e7bc3f1efc5f098534bce73589835b8273b9a0 and the token ID is 339.
If you call the function tokenURI(uint256 tokenId), it retrieves data from a mapping mapping (uint256 => string) private _tokenURIs.
The string value for the ID 339 is https://metadata.thetwentysix.io/cryptocats/339. And yes, it is a (off-chain) JSON file that contains link to the actual image https://cryptocats.thetwentysix.io/contents/images/cats/339.png

Hiding input variables from ever being recorded in a transaction

I'm working on something, just a proof of concept, where people are rewarded for sharing metadata about their IP location. In this case (please ignore the code errors for now), someone would submit their ip, I would send it to an oracle that would resolve it and send back metadata about the ip, then would send the address and metadata to another contract.
This is the naive attempt at pseudo code (or non-compiling, at least) I've come up with:
pragma solidity ^0.4.0;
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
contract IpMeta is usingOraclize {
uint public metadata;
function Metadata(bytes32 _ipAddress) public {
update(_ipAddress);
}
function __callback(bytes32 myid, string result) public {
if (msg.sender != oraclize_cbAddress()) revert();
bytes32 ipMetadata = result;
/* send address and result to another contract */
}
function update(bytes32 ipAddress) public payable {
oraclize_query("URL", "xml(https://ipresolver.com?ipresolve=" . ipAddress . ")");
}
}
The goal here is to allow people to prove something about their IP address (country, provider, etc) without the actual IP address being stored with the wallet address in the transaction or anywhere else. Is there a way to hide input data? I'm at a loss on research, and it seems like it would be a really useful function if possible. The im/practicalities of anything other than how to keep input data hidden or inaccessible aren't important.
Thanks,
Mark
The EVM is essentially a network composed of nodes of computers. Anyone can run their own node and your smart contract code will get run on those computers if they have a valid node that can receive the transactions. And since the data will also get transmitted to those computers, the owner that sees the code running in his/her computer will eventually have the power to look into the process getting run(by overseeing network, inspecting memory, etc.).
So from my understanding, the difficulty of doing this depends on the implementation of a Ethereum node. Actually Ethereum's protocols handles some level of security by encrypting the p2p connection. However, what makes all these obsolete in your context is that, the input data is serviced and revealed by services like etherscan(random example). I think it's still possible to achieve want you want, but it will only be a workaround and it will be difficult.
I think of Ethereum and its EVM as a transparent computer, basically the data it receives and sends are not secure at all. If you want to achieve security, that's the thing to achieve in somewhere else, for example process the ip related jobs in some other secure place(trusted 3rd party), then store the data without ip onto the blockchain. That's the best I can think of.

Few questions about smart contract I created (just start learning)

I just started learning solidity and have some questiones about the smart contract I created for pratice/fun.
Please let me know if any of my concepts are inaccurate, appreciate for all the advices and suggestiones.
Description:
the concept of this smart contract is really simple, whoever send the bigger amount of ether into the contract wins, it will pair you with whoever is before you (if no one is before you, you are player_one) and it will reset after 2 player are played (so it can be played again)
Code:
contract zero_one {
address public player_one;
address public player_two;
uint public player_one_amount;
uint public player_two_amount;
function zero_one() public{
reset();
}
function play() public payable{
//Scenario #1 Already have two player in game, dont accpet new player. do I even need this check at all? since smart contract execute serially i should never face this condition?
if(player_one != address(0) && player_two != address(0)) throw;
//Scenario #2 First player enter the game
else if(player_one == address(0) && player_two == address(0)){
player_one=msg.sender;
player_one_amount = msg.value;
}
//Scenario #3 Second player join in, execute the game
else{
player_two = msg.sender;
player_two_amount = msg.value;
//check the amount send from player_one and player two, whoever has the bigger amount win and get their money
if(player_two_amount>player_one_amount){
player_one.transfer(player_one_amount+player_two_amount);
reset();
}
else if(player_two_amount<player_one_amount){
player_two.transfer(player_one_amount+player_two_amount);
reset();
}
else{
//return fund back to both player
player_one.transfer(player_one_amount);
player_two.transfer(player_two_amount);
reset();
}
}
}
function reset() internal{
player_one = address(0);
player_two = address(0);
player_one_amount = 0;
player_two_amount = 0;
}
}
Questions
When sending ether back to users, do I need to calcualate how much
gas is going to take? or would smart contract automatically deduct
the gas from the amount i am going to send
Is it correct to set reset() as interal since i only want it to be
called within the smart contract, it shouldn't be called by anyone else
Would Scenario#1 ever happen? since from what I understand
smart contract do not have to worry about race condition and it
should never be in that state?
Is adding playable to play correct? ( since user are going to send ether with this call)
Is using throw a bad practice? (warning on remix)
transfer vs send, why is it better to use transfer?
I coded this smart contract as a practice. I can already see that if
someone want to game the system, he could just wait for someone to be player_one and check the amount player_one send(after the block is mined) and just send a bigger sum than that. Is there anyway this exploit could be stopped? Is there other security/flaws I did not see?
Thanks!
When sending ether back to users, do I need to calcualate how much gas
is going to take? or would smart contract automatically deduct the gas
from the amount i am going to send
The gas limit specified when executing a transaction needs to cover all activity end-to-end. This includes calls out to other contracts, transfers, etc. Any gas not used after the transaction is mined is returned to you.
Is it correct to set reset() as interal since i only want it to be
called within the smart contract, it shouldn't be called by anyone
else
internal is fine for what you're intending to do. But, it's more like protected access. A sub-contract can call internal methods. private provides the strictest visibility.
Would Scenario#1 ever happen? since from what I understand smart
contract do not have to worry about race condition and it should never
be in that state?
No, it should not happen. You are correct that transactions are processed serially, so you don't really have to worry about race conditions. That doesn't mean you shouldn't have this sort of protection in your code though...
Is adding playable to play correct? ( since user are going to send
ether with this call)
Yes. Any method that is expecting to receive wei and uses msg.value needs to be marked as payable.
Is using throw a bad practice? (warning on remix)
throw is deprecated. You want to use one of revert, require, assert as of 0.4.13. The one you use depends on the type of check you're doing and if gas should be refunded. See this for more details.
transfer vs send, why is it better to use transfer?
send and transfer are similar. The difference is that send limited the amount of gas sent to the call, so if the receiving contract tried to execute any logic, it would most likely run out of gas and fail. In addition, failures during send would not propagate the error and simply return false. Source
I coded this smart contract as a practice. I can already see that if
someone want to game the system, he could just wait for someone to be
player_one and check the amount player_one send(after the block is
mined) and just send a bigger sum than that. Is there anyway this
exploit could be stopped? Is there other security/flaws I did not see?
Security is a much more in depth topic. Any data sent in a transaction is visible, so you can't hide the exploit you mentioned unless you use a private blockchain. You can encrypt data sent in a transaction yourself, but I don't believe you can encrypt sending ether.
In terms of other security issues, there are several tools out there that perform security checks on contracts. I'd suggest looking into one of those. Also, read through the security considerations page on the Solidity documentation.