The following is some stripped down sample code which I am using to formulate my question. This pertains to the Youtube Video by Patrick Collins entitled: How to make NFT Art with On-Chain Metadata | FULL HARDHART / JS TUTORIAL! (w/ Polygon & Opensea)
contract RandomSVG is ERC721URIStorage, VRFConsumerBase {
....
....
function create() public returns (bytes32 requestId) {
requestId = requestRandomness(keyhash, fee);
...
...
}
function fulfillRandomness(bytes32 requestId, uint256 randomNumber)
internal
override
{
...
...
_safeMint(nftOwner, tokenId);
...
}
}
The RandomSVG is a contract that will create random NFTs.
Question 1 :
I read the documentation but i'm still unable to understand. What does the _safeMint() function exactly do ?
Question 2: At what point in the contract should the _safeMint() function be called ?
In his example, Patrick is using the _safeMint() function inside the fulfillRandomness() callback. Why is the _safeMint() called even before the Image has been created ? Shouldn't it be called After the TokenURI has been created ?
_safeMint() is used along with IERC721Receiver that checks if you are sending the minted token to a Contract that is capable to manage NFTs or not. This is to prevent tokens to be lost.
Related
I'm trying to retrieve the total supply of an ERC1155 SmartContract. This code was made by my friend and has been deployed. He took the code from OpenZeppelin with Burnable and Pausable presets.
The function totalSupply that I am trying to retrieve exists in the code. But, when I see the ABI, the totalSupply does not included.
(Sorry for small screenshot. Please see this screenshot in the new tab)
MyErc1155Contract compiled
This is where to get the ABI
Full code is here: click_this_to_go_to_pastebin
Then I am trying to write smartcontract to retrieve the totalSupply;
pragma solidity ^0.8.0;
contract TotSup {
uint256 public hasilBal;
uint256 public hasil;
function balanceOf(address erc1155_address,
address user_address,
uint256 nft_id) public {
(bool successA, bytes memory resultA) =
erc1155_address.call(abi.encodeWithSignature(
"balanceOf(address,uint256)",
user_address,
nft_id
));
hasil = abi.decode(resultA, (uint256));
}
function bal(address erc1155_address, uint256 nft_id) public {
(bool successA, bytes memory resultA) =
erc1155_address.call(
abi.encodeWithSignature("totalSupply(uint256)", nft_id
));
hasilBal = abi.decode(resultA, (uint256));
}
}
I test my idea with writing another function balanceOf and it works perfectly.
And for the totalSupply in function bal is fail.
Is it possible to retrieve or calling function which is not included in the ABI? If yes, how to achieve that? And last, why call balanceOf still need for paying gas for just retrieving the data?
When a function exists in the code when you compile the code it reflects in the ABI, Without the function signature, you can't call the function.
As for your second answer, balanceOf in TotSup will cost you gas as it is not a view function.
I'm going through the source code for the ERC-1155 token standard and I came across this block of code
bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26;
function supportsInterface(bytes4 _interfaceID) override external view returns (bool) {
if (_interfaceID == INTERFACE_SIGNATURE_ERC165 ||
_interfaceID == INTERFACE_SIGNATURE_ERC1155) {
return true;
}
return false;
}
I don't quite understand what the benefit of this function is used for.
Also, where do you get the INTERFACE_SIGNATURE constants from?
Could someone please explain?
I believe there is a good explanation for this on openzeppelin docs.
but just to give a short answer, suppose you sent ERC20 tokens to a contract that lacks the ability to transfer it so these tokens are forever locked in the contract. To avoid this kind of things, when you do a safetranser it will first check whether the receiver is capable of receiving it or not and in that case this function is called.
As for INTERFACE_SIGNATURE you can give it a read here.
I am learning solidity in cryptozombies. I just finished 12 chapters with the good understanding. but, I don't understand the events concept. I want to understand the full code. can somebody help me with that??
pragma solidity >=0.5.0 <0.6.0;
contract ZombieFactory {
event NewZombie(uint zombieId, string name, uint dna);
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function _createZombie(string memory _name, uint _dna) private {
uint id = zombies.push(Zombie(_name, _dna)) - 1;
emit NewZombie(id, _name, _dna);
}
function _generateRandomDna(string memory _str) private view returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_str)));
return rand % dnaModulus;
}
function createRandomZombie(string memory _name) public {
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);
}
}
The function of the event is that when the caller invokes this function, an additional logs will be added to the transaction content.
For a common example of ERC20 tokens, if the contract creator didn't add the event function when writing the Transfer function, something interesting would happen, the blockchain browser would not display the number of Hodlers properly and it would not show the detailed transaction history of the user-user transfer of ERC20 tokens.
Let's conclude that adding the event function will make it easier for the searcher on the blockchain browser to understand or analyze each transaction, but it will also make it easier for the searcher on the blockchain to find transactions or filter them for some arbitrage :)
Think of Events as the code piece that you put in a place where you want to be notified instantly if something happens there.
contract test{
function Alert() public returns (string memory) {
string memory str = "Alert! Do Something.";
return str;
}
}
for example in this code here you would want to be notified on your end-user screen so in order to that you would want your front-end to be able to get this info! right? and how would you go about doing that? by creating an event with which your front-end can interact with (particularly read from). Therefore you would modify the above code to add event to this as follows:
contract test{
event readAlert(string str);
function Alert() public returns (string memory) {
string memory str = "Alert! Do Something.";
return str;
emit readAlert(str);
}
}
After doing this you can now use the event you just created to do something with the info passed to it on you app front-end.
Let me know if you need further explanation. :)
As it is now, anyone can call the setMyString function in the FirstContract. I'm trying to restrict access to that function to an instance of SecondContract. But not one specific instance, any contract of type SecondContract should be able to call setMyString.
contract FirstContract{
String public myString;
function setMyString(String memory what) public {
myString=what;
}
}
contract SecondContract{
address owner;
address firstAddress;
FirstContract firstContract;
constructor(address _1st){
owner=msg.sender;
firstAddress=_1st;
firstContract=FirstContract(firstAddress);
}
function callFirst(String memory what){
require(msg.sender==owner);
firstContract.setMyString("hello");
}
}
Solidity currently doesn't have an easy way to validate an address against an interface.
You can check the bytecode, whether it contains the specified signatures (of the public properties and methods). This requires a bit larger scope than a usual StackOverflow answer, so I'm just going to describe the steps instead of writing the code.
First, define the desired list of signatures (1st 4 bytes of keccak256 hash of the name and arguments datatypes) that you're going to be looking for. You can find more info about signatures in my other answers here and here.
An example in the documentation shows how to get any address's (in your case msg.sender) bytecode as bytes (dynamic-length array).
You'll then need to loop through the returned bytes array and search for the 4-byte signatures.
If you find them all, it means that msg.sender "implements the interface". If any of the signatures is missing in the external contract, it means it doesn't implement the interface.
But... I'd really recommend you to rethink your approach to whitelisting. Yes, you'll need to maintain the list and call setIsSecondContract() when a new SecondContract wants to call the setMyString() function for the first time. But it's more gas efficient for all callers of the FirstContract's setMyString() function, as well as easier to write and test the functionality in the first place.
contract FirstContract{
String public myString;
address owner;
mapping (address => bool) isSecondContract;
modifier onlySecondContract {
require(isSecondContract[msg.sender]);
_;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function setIsSecondContract(address _address, bool _value) public onlyOwner {
isSecondContract[_address] = _value;
}
function setMyString(String memory what) public onlySecondContract {
myString=what;
}
}
I'm building an application that is comprised of 3 smart contracts. The aim is to have the controller control the other two (contract A and B in the image). Previously, if I wanted to restrict the access to a smart contact, I would do it through a modifier
Example:
modifier onlyController {
require(msg.sender == controller);
_;
}
At contact creation, the smart contract would set controller to be equal to whatever ethereum address I want to make these calls ( for example the address that deployed the smart contract). The issue is that now I want the address of the controller smart contract to be the controller (in the modifier). How would it be best to do this considering I want to deploy these set of smart contacts at the same time using truffle. What would be the best way to link these, so that the controller smart contract is only able to make calls to A and B. Moreover, how does the controller have to be implemented so that the user can call function in A and B going through the controller ( so the user calls a function in the controller, then the controller calls the corresponding function in A or B)?
I am no expert in Solidity. But trying to answer as I find it little bit interesting.
You seem to be trying to implement a proxy pattern which is very common in other programming languages like java in such a way that you are providing very restricted access to certain classes in this case contracts.
In Proxy design pattern both the proxy and the class to be restricted would be implementing the same interface! I do not know much about your smart contract details.
Assuming Contract A and B implementing the same interface:
Lets assume the interface is Base.
interface Base{
function getValue() external view returns (string);
}
I need to provide controlled access to the ContractA and ContractB so only the controller could call. So lets create a modifier.
contract ControlledAccess{
address controller;
constructor() public {
controller = msg.sender;
}
modifier onlyController() {
require(msg.sender == controller);
_;
}
}
Now ContractA and ContractB should implement interface Base and inherit ControlledAccess contract.
contract ContractA is Base, ControlledAccess{
function getValue() public view onlyController returns (string){
return "Hi";
}
}
contract ContractB is Base, ControlledAccess{
function getValue() public view onlyController returns (string){
return "Hello";
}
}
In order to set the controller address to be the ProxyController address, ProxyController itself should create these contracts in its constructor. As our ProxyController contract should be able to control more than 1 contract, I think mapping might be a good choice.
contract ProxyController is Base{
string public contractKey = "a";
mapping(string => Base) base;
constructor() public {
base["a"]=new ContractA();
base["b"]=new ContractB();
}
function setContractKey(string _contractKey) public{
contractKey = _contractKey;
}
function getValue() public view returns (string){
return base[contractKey].getValue();
}
}
so you can switch to A & B via setContractKey.
Assuming there is no common functionalities between A and B :
Remove the interface in the above example.Then implement something like this.
contract ProxyController{
ContractA a;
ContractB b;
constructor() public {
a=new ContractA();
b=new ContractB();
}
function AgetValue() public view returns (string){
return a.getValue();
}
function BgetValue() public view returns (string){
return b.getValue();
}
}
I tested this and it seems to be working fine. However I am not sure of other issues like performance etc.
Can't you easily set up the controller contract as
contract ControllerContract is ContractA, ContractB {
...
}
Thus giving it access to the functions in both contract A and contract B?
I'm not sure why this way would be worse than how you are describing.
You can find some solutions at the following links:
1.) https://ethereum.stackexchange.com/questions/36524/multiple-smart-contracts
2.) https://ethereum.stackexchange.com/questions/37055/where-how-to-host-several-connected-smart-contracts
A complete article on Interactions between Smart Contracts with Solidity:
https://zupzup.org/smart-contract-interaction/
A link to another article and a sample project: https://hackernoon.com/ethereum-smart-contracts-lifecycle-multiple-contracts-message-sender-e9195ceff3ec
Hope it solves your problem. Also, you can join this community for exclusivity: https://ethereum.stackexchange.com/