Lock transfer of erc721 NFT - solidity

Hi all I am building a blockchain-based game around an NFT project and am looking to understand if it's possible to implement the following.
Have a method on the NFT contract that when called can locks the transfer of all minted NFT's for a period. A bit like a game of tag than when your tag the contract all the (NFT / players) cant (move /transfer)
I assume I would need overide the transfer method then do a boolean check.
Something like
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
if(!isLocked){
safeTransferFrom(from, to, tokenId, "");
}
}
Will this work as I expect and is there any issues with this and would override the transfer method especially around security etc.
Sorry for such a broad question
Thanks

From the context, it seems like you're using the OpenZeppelin implementation. If that's the case, you can override their _beforeTokenTransfer() function, which is effectively called from all functions performing token transfer (as there is multiple of them).
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyCollection is ERC721 {
constructor() ERC721("MyCollection", "MyC") {
_mint(msg.sender, 1);
}
// needs to be unlocked for the `_mint()` function in constructor
bool locked = false;
function setLocked(bool _locked) external {
locked = _locked;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal override {
require(!locked, "Cannot transfer - currently locked");
}
}
If you're using other or custom implementation, or chose to only override the publicly visible functions, make sure that there is no other public or external function allowing the transfer without the lock mechanism.
Also few notes to your current code:
You probably won't need the virtual keyword. It allows the function to be further overridden. Unless you're expecting to override this function as well, you can safely remove the keyword.
You're calling the parent function with the same name but different argument set. If you wanted to call the parent function with the same name and the same argument set (assuming it's defined), you'd need to use the super keyword (same as in Java): super.safeTransferFrom(from, to, tokenId);

Related

passing msg.data in external contract using delegate call

I am going through the ethernaut ctf challeneges and I am trying to take ownership of this contract through my own smart contract, here is the target code:
pragma solidity ^0.6.0;
contract Delegate {
address public owner;
constructor(address _owner) public {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) public {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}
My assumption is that you can exploit this code and take ownership by passing msg.data in the Delegation contract that corresponds to the pwn() function in the Delegate contract (using delegate call this will allow us to take ownership of the delegation contract). My problem is passing in the msg.data and I am not entirely sure how to do it properly, here is my attempt:
contract ownerAttack {
function attack(address payable _victim) public payable {
address to = payable(_victim);
(bool sent, ) = to.call{value: msg.value}(abi.encodeWithSignature("pwn()"));
require(sent , "transfer failed");
}
receive()external payable{
}
However the transfer fails, thanks in advance for the help
You have correctly identified the approach to this; we have to send in the function selector of the target contract (Delegate) while making a call to the immediate contract (Delegation).
For this, we can Web3JS or EtherJS. Ethernaut console supports Web3JS so we will go with that here.
First, we have to calculate the selector for the pwn() function.
const selector = web3.eth.abi.encodeFunctionSignature("pwn()")
Second, we have to make the call to Delegation, but call pwn() as its function. This way, the fallback function is triggered, which then makes the delegate call to the function whose selector is in msg.data of the transaction. Thus, pwn() function of Delegate contract is called.
To make the call, we simply use sendTransaction like:
await web3.eth.sendTransaction({from: player, to: contract.address, data: selector})
And this should answer your question.
I think Hasan Answer will work, but if you want to do the attack entirely inside solidity, I think you might be able to get the function signature by doing:
bytes4 encodedSignature = bytes4(keccak256("pwn()"));
Hashing with keccak256 and then casting it to bytes4 is exatcly how Solidity generates function signatures, so this should work.
But after some research it looks like you can also use this to retrieve it:
Delegate(0).pwn.selector
Then use the returned value to make the attack.
The following also works:
bytes memory selector = abi.encodeWithSignature("pwn()");
(bool success, ) = address(c).call(selector);
c is the address of the contract which makes the delegatecall

What is the point of inheriting from ERC271 contract?

I have just started Solidity. For this question, I think it's useful if I first state my understanding of inheritance: If Contract B inherits from Contract A (ie. in contractB.sol we have
contract B is A {...
}
then Contract B will have access to functions from contract A.
Also, from my understanding, if I want to use some functions from another contract by someone else, I would have the following in my code:
contract someoneElsesInterface {
function someFunction() returns(something) }
contract myContract {
someoneElsesInterface someoneElsesContract = someonElsesInterface(address);
value = someoneElsesContract.someFunction();
}
My confusion arises when trying to implement the ERC721 standard. First, I must save the erc721.sol file in my directory; the file contains
contract ERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
}
And then in a separate file, I must inherit from the ERC721 contract and then define the content of the four functions balanceOf, ownerOf, transferFrom, approve; as well as emitting the Transfer and Approve events. So the following:
contract myContract is ERC721 {
function balanceOf...
function ownerOf...
function transferrFrom...
...
}
This is what I don't understand: Why is ERC721 not inheriting from myContract, since we are defining functions in myContract and just stating the function name and returns in ERC721 like my example above? What even is the point of the ERC721 contract and having myContract inherit from ERC721, when we already defined all the function content in myContract? When working from on the front end, do I call the functions from myContract or from ERC721?
I hope my question is clear, if not I can clarify in comments. Thank you in advance for the replies.
First of all, you don't inherit an interface, but you implement it. In an interface contract, you don't define, you declare. You declare functionality, inputs, and outputs.
An interface can't inherit from a concrete (actual) contract. Only interfaces can inherit each other. If you think about it, concrete contracts contain more information than interfaces, how can an interface inherit from a concrete contract?
Generally speaking interfaces are contracts between user and program, and this is also true for Solidity. They guarantee a certain functionality to users. By implementing ERC721, you are declaring that your contract is ERC721 compatible. Because of this, the user does not need to know about your contract's implementation details, instead, they can call your contract using the ERC721 interface.
Consider following:
ContractA { ... }
vs
ContractB is ERC721 { ... }
Let's say both contracts are implementing ERC721 functionality.
To be able to call ContractA for ERC721 interaction, I have to import its ABI and verify that it is compatible. For example, I would call it like:
ContractA(ADDRESS_OF_CONTRACT_A).safeTransferFrom(...)
On the other hand to call ContractB, only thing I need is ERC721 ABI, I don't need to know about ContractB. So I can do:
ERC721(ADDRESS_OF_CONTRACT_B).safeTransferFrom(...)
Before I end, I would like to emphasize that your question is not actually about Solidity or smart contracts, but it is about object-oriented programming, inheritance, and interfaces. I recommend you to read about it more to have a better understanding of the concept.

Ways to get the value of mapping public?

I have this piece of code, but I dont have implemented a view returns function.
mapping (uint256 => TokenTimeLockInfo) public locks;
struct TokenTimeLockInfo {
Token token;
address beneficiary;
uint256 amount;
uint256 unlockTime;
}
I can access the value way web3js are possible?
Or do I need another contract to implement a view returns?
Since the property is public, you can access it using the getter function automatically generated by Solidity compiler.
const myContract = new web3.eth.Contract(abiJson, contractAddress);
// returns value of the mapping for the key `0`
const info = await myContract.methods.locks(0).call();
Docs:
https://docs.soliditylang.org/en/v0.8.6/contracts.html#getter-functions
https://web3js.readthedocs.io/en/v1.3.4/web3-eth-contract.html#methods-mymethod-call

Why does Solidity suggest me to implement a receive ether function when I have a fallback function?

The recent change in Solidity changed the fallback function format from just function() to fallback(), which is pretty nice for beginners to understand what is going on, but I have a question about a suggestion that the compiler gives me when I implement such a fallback.
For example, a piece of code from my project:
pragma solidity ^0.6.1;
contract payment{
mapping(address => uint) _balance;
fallback() payable external {
_balance[msg.sender] += msg.value;
}
}
Everything goes fine, but the compiler suggests that:
Warning: This contract has a payable fallback function, but no receive ether function.
Consider adding a receive ether function.
What does it mean by a receive ether function? I tried looking it up and many examples I could find is just another fallback function.
I am using version 0.6.1+commit.e6f7d5a4
As a complement to the accepted answer, here's how you should define the unnamed fallback and receive functions to solve this error:
contract MyContract {
fallback() external payable {
// custom function code
}
receive() external payable {
// custom function code
}
}
According to solidity version 0.6.0, we have a breaking change.
The unnamed function commonly referred to as “fallback function” was split up into a new fallback function that is defined using the fallback keyword and a receive ether function defined using the receive keyword.
If present, the receive ether function is called whenever the call data is empty (whether or not ether is received). This function is implicitly payable.
The new fallback function is called when no other function matches (if the receive ether function does not exist then this includes calls with empty call data). You can make this function payable or not. If it is not payable then transactions not matching any other function which send value will revert. You should only need to implement the new fallback function if you are following an upgrade or proxy pattern.
https://solidity.readthedocs.io/en/v0.6.7/060-breaking-changes.html#semantic-and-syntactic-changes

get contract creator's address in a different separate smart contract

I want to create a dApp where one can do certain things related to a contract they've deployed. let's say it'll be used to manage a token listing site.
I need to figure out how to verify that the address that's calling the functions matches the address that created a particular contract.
eg. 0x01 is the contract creator of Contract A
0x01 calls a function along with the parameter of Contract A's contract address in Contract B
A function within Contract B then finds the contract creator's address of Contract A somehow and matches that against 0x01
Is this possible to do in solidity?
Code
pragma solidity ^0.4.20;
contract A {
address private owner_;
function A() public {
owner_ = msg.sender;
}
function getOwner() public view returns (address) {
return owner_;
}
}
contract B {
function findAsOwner() public view returns (bool) {
require(A(address of contract A).getOwner() == msg.sender);
return true;
}
}
I tested it on my remix. I called findAsOwner() and it passed the require part and returned true. You may use this pattern.