How to make check if a key exists in mapping or not in Solidity when value is of type enum? - solidity

I have the following contract in solidity.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract PocketCrypto {
enum Role{ GUARDIAN, WARD}
mapping(address => Role) public role;
function setRole(Role _role) public {
role[msg.sender] = _role;
}
}
I want to check if for a given address a Role is set or not. But since default value for mapping will be 0, and for enum it will mean first Role, how do I accomplish this?

You can extend the enum to reflect the 0th index (default) value as none.
enum Role{ NONE, GUARDIAN, WARD}

Related

Solidity: Internal or recursive type is not allowed for public state variables, Cannot Expose public mapping containing struct

I don't understand why this doesn't work when I can see it works in the existing bravo contracts
I'm trying to support inhertance of a public property I have structs that look like so:
abstract contract Governance {
struct Proposal {
/// #notice Unique id for looking up a proposal
uint id;
/// #notice Creator of the proposal
address proposer;
/// #notice the ordered list of target addresses for calls to be made
address[] targets;
/// #notice Receipts of ballots for the entire set of voters
mapping (address => Receipt) receipts;
//...
}
/// #notice Ballot receipt record for a voter
struct Receipt {
/// #notice Whether or not a vote has been cast
bool hasVoted;
/// #notice Whether or not the voter supports the proposal or abstains
uint8 support;
/// #notice The number of votes the voter had, which were cast
uint96 votes;
}
}
I'm trying to expose a public mapping like so:
mapping(uint256 => ProposalVote) public bravoProposals;
When I try to expose this I get an error:
TypeError: Internal or recursive type is not allowed for public state variables.
I'm using solidity 0.8.9? This should work, what am I missing here?
I'm not sure why this is the case, but it seems solidity can't expose public mapping whose do not start at a "definitive" point
By adding an arbitrary value with a definitive length, it can be exposed.
struct ProposalVote {
bool isTrue;
uint256[] votes;
mapping(address => bool) hasVoted;
}
Note: This answer is based on observations and I would prefer a better answer

Is there a way to check if msg.sender owns some collection?

Is there a way to do the following:
function registerCollection(address __collection) public {
require(msg.sender == IERC721(__collection).owner), "Does not own contract");
...[rest of function]...
}
Is there a way, within solidity, to access the owner field of another contract. So I do not mean owns an NFT of another collection, which could be done by calling .ownerOf(tokenId) and comparing to msg.sender. I want to get the actual owner of the contract.
It's possible that a collection has a address public owner, especially if it inherits from Openzeppelin's Ownable library.
So you are able to get it like this:
interface IOwnable {
function owner() external view returns(address)
}
IOwnable(__collection).owner()
Though be aware that if a collection doesn't gave a public owner the call will revert.

What is the difference between msg.sender and from address in solidity smart contracts, are both the same who are initiating the transaction?

I am just starting out with the solidity and the smart contracts but i am confused like what is the difference between msg.sender and from address in ERC20 guidelines for the creation of smart contracts
msg.sender refers to the account that is calling the function it could be an EOA (Externally Owned Account) or a contract Address.
from is a parameter for the function.
Example:
// Send an amount from any address to any address
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
_transfer(from, to, amount);
return true;
}
// Send an amount from the function caller to any address
function transferFromCaller(address to, uint256 amount) public virtual override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
msg.sender is actually the address that you use when calling the function. This is a global variable that you don't define. As far as I understant, in a Token contract, "from" is the address of the account you want to use to spend some amount of token.

Why do constructors have to have a public and not internal visibility?

Only initializes the contract, and I don't understand why it is not an internal function. With this, is more cheap the cost of the gas insted implementing a public function
API from Solidity :
// This is the constructor which registers the
// creator and the assigned name.
constructor(bytes32 _name) public {
// State variables are accessed via their name
// and not via e.g. `this.owner`. Functions can
// be accessed directly or through `this.f`,
// but the latter provides an external view
// to the function. Especially in the constructor,
// you should not access functions externally,
// because the function does not exist yet.
// See the next section for details.
owner = msg.sender;
// We do an explicit type conversion from `address`
// to `TokenCreator` and assume that the type of
// the calling contract is `TokenCreator`, there is
// no real way to check that.
creator = TokenCreator(msg.sender);
name = _name;
}

What OOP Design Pattern can I use to allow for different types of Address Classes?

I have a base Address class which defines basic address properties and acts as an CRUD object:
Name
Company
Address Line 1
Address Line 2
Address Line 3
City
State
Postal Code
Country
I have a 'ShipToAddress' class which extends Address and includes two more properties:
Phone Number
Email Address
Address includes validation methods for each of its properties, and ShipToAddress includes validation for only its properties (Phone Number and Email Address).
My issue is, I also want to account for both USA and International addresses for both of these classes without duplicating code, so that I can have different validation methods for State and Postal Code. USA State validation would ensure that the value is one of the 50 States. International validation would simply ensure that it does not exceed the length allowed in the database.
How can I design this to allow for any number of different types of addresses (USA, Canada, etc.) but also have the base Address class and the ShipToAddress class, without duplicating the code? I basically want the following:
Address Base Class
ShipToAddress
USAAddress
USAShipToAddress
***Address
***ShipToAddress
Define AddressValidator as a separate interface.
public interface AddressValidator {
boolean validateAddress(ShipToAddress add);
}
Create different implementations of it - USAAddressValidator, CanadaAddressValidator etc.
You can have a Factory to give you the appropriate AddressValidator object based on the country.
public class AddressValidatorFactory {
public static AddressValidator GetValidator(Address address) { ... }
}
You should also consider whether ShipToAddress should extend Address or contain it. Are you going to pass ShipToAddress object where Address is expected? If not, then there is no need for ShipToAddress to extend Address.
I would probably make it a template, with the validator passed as a template parameter:
class US_validator { /* ... */ };
class Int_validator { /* .. */ };
template <class Validator>
class Address {
// ...
};
template <class Validator>
class Shipping_address : public Address {
// ...
};
typedef Address<US_validator> US_Address;
typedef Address<Int_validator> Int_Address;
typedef Shipping_address<US_validator> US_Shipping_address;
typedef Shipping_address<Int_validator> Int_Shipping_address;
Another possibility would be to use multiple inheritance, with the validator as a base class.
class US_validator { /* ... */ };
class Int_validator { /* ... */ };
class Address { /* ... */ };
class Shipping_Address : public Address { /* ... */ };
class US_Shipping_Address : public US_validator, public Shipping_Address { /* ... */ };
class Int_Shipping_Address : public Int_validator, public Shipping_Address { /* ... */ };
The latter isn't used nearly as often nor (probably) viewed as favorably by most, but can still work perfectly well.