I'm new to Solidity.I've got an error from compiling the above code.
browser/EHRs.sol:18:9 :Error:Undeclared identifier.require(msg.sender = dotor);
Hopefully someone can give some guidance
pragma solidity ^0.4.0;
contract postRecord {
bytes32 public patientRecords;
address public doctor;
function Person() private{
doctor = msg.sender;
}
struct patient {
address client;
bool consent;
bytes32 name;
}
function setPatientRecords(bytes32 _patientRecords) public {
patientRecords = _patientRecords;
}
event Post(bytes32 patientRecords, address doctor);
modifier rightPerson {
require (msg.sender = doctor);
_;
}
function getRecords()public payable{
Post(patientRecords, doctor);
}}
Firstly use == to compare values, and secondly pass exception message as second parameter in require (you can pass empty string)
modifier rightPerson {
require (msg.sender == doctor, "");
_;
}
require()
Have a look at this solution
modifier rightPerson {
require (doctor == msg.sender);
_;
}
The problem is that inside the require statement, you are performing an assignment instead of a comparision.
require (msg.sender = doctor); This assigns doctor to msg.sender which is incorrect.
Instead, you should use the equality comparison operator == to perform the comparision.
require (msg.sender == doctor);
And as an answer above suggested, use a revert string for better user and dev experience.
require (msg.sender = doctor, "PostRecord: Caller must be a doctor.");
Also, write the contract name with a capital first letter: PostRecord instead of postRecord.
Related
I got a little confused when trying to solve this level and I got even more confused when I read this solution.
I thought that the contract object loaded in the browser console was the PuzzleWallet contract, because when I look at its ABI, there are all the functions from that contract and none from the PuzzleProxy. And the PuzzleWallet does not inherit from any other contract. I don't understand how it is possible to call proposeNewAdmin() function from the PuzzleProxy contract, if it does not inherit from PuzzleProxy...
On the other hand, if the contract object in the browser console is the PuzzleProxy, why there are all the functions from the PuzzleWallet in the ABI and none from the PuzzleProxy?
Here is the Ethernaut level.
The contracts are:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "#openzeppelin/contracts/math/SafeMath.sol";
import "#openzeppelin/contracts/proxy/UpgradeableProxy.sol";
contract PuzzleProxy is UpgradeableProxy {
address public pendingAdmin;
address public admin;
constructor(address _admin, address _implementation, bytes memory _initData) UpgradeableProxy(_implementation, _initData) public {
admin = _admin;
}
modifier onlyAdmin {
require(msg.sender == admin, "Caller is not the admin");
_;
}
function proposeNewAdmin(address _newAdmin) external {
pendingAdmin = _newAdmin;
}
function approveNewAdmin(address _expectedAdmin) external onlyAdmin {
require(pendingAdmin == _expectedAdmin, "Expected new admin by the current admin is not the pending admin");
admin = pendingAdmin;
}
function upgradeTo(address _newImplementation) external onlyAdmin {
_upgradeTo(_newImplementation);
}
}
contract PuzzleWallet {
using SafeMath for uint256;
address public owner;
uint256 public maxBalance;
mapping(address => bool) public whitelisted;
mapping(address => uint256) public balances;
function init(uint256 _maxBalance) public {
require(maxBalance == 0, "Already initialized");
maxBalance = _maxBalance;
owner = msg.sender;
}
modifier onlyWhitelisted {
require(whitelisted[msg.sender], "Not whitelisted");
_;
}
function setMaxBalance(uint256 _maxBalance) external onlyWhitelisted {
require(address(this).balance == 0, "Contract balance is not 0");
maxBalance = _maxBalance;
}
function addToWhitelist(address addr) external {
require(msg.sender == owner, "Not the owner");
whitelisted[addr] = true;
}
function deposit() external payable onlyWhitelisted {
require(address(this).balance <= maxBalance, "Max balance reached");
balances[msg.sender] = balances[msg.sender].add(msg.value);
}
function execute(address to, uint256 value, bytes calldata data) external payable onlyWhitelisted {
require(balances[msg.sender] >= value, "Insufficient balance");
balances[msg.sender] = balances[msg.sender].sub(value);
(bool success, ) = to.call{ value: value }(data);
require(success, "Execution failed");
}
function multicall(bytes[] calldata data) external payable onlyWhitelisted {
bool depositCalled = false;
for (uint256 i = 0; i < data.length; i++) {
bytes memory _data = data[i];
bytes4 selector;
assembly {
selector := mload(add(_data, 32))
}
if (selector == this.deposit.selector) {
require(!depositCalled, "Deposit can only be called once");
// Protect against reusing msg.value
depositCalled = true;
}
(bool success, ) = address(this).delegatecall(data[i]);
require(success, "Error while delegating call");
}
}
}
The contract.abi object on the browser console is:
I understand the concept of proxy patterns. But I thought that it would be done via delegatecall() functions. For example, the addToWhiteList() function on the PuzzleWallet contract would be called by a function as follows on the PuzzleProxy contract:
function addToWhitelist(address _add) external {
puzzleWalletAddress.delegatecall(abi.encodeWithSignature("addToWhitelist(address)", _add);)
}
Hopefully my question here is not as confusing as I got while trying to solve this level :)
Appreciate very much if anyone coould help me! Thanks!
I also got confused by the same thing :)
The answer is that they created the Web3 contract object with the ABI of the logic contract but with the address of the proxy contract so you can interact with the logic as if there wasn't a proxy pattern under the hood.
In reality it is calling the proxy contract with the data of a function of the logic contract. As the function doesn't exist in the proxy, its fallback function runs and redirects the call to the logic contract via delegatecall.
So if you want to call proposeNewAdmin() in the proxy, call the contract mounted in the console (aka the proxy contract) but instead of using any function from the ABI defined there (which is the logic abi), make a generic transaction calling proposeNewAdmin(). As the function does exist in the proxy, it won't trigger the fallback.
web3.eth.abi.encodeFunctionSignature("proposeNewAdmin(address)");
> '0xa6376746'
web3.eth.abi.encodeParameter("address", player);
> '0x000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942'
contract.sendTransaction({ data: '0xa6376746000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942' });
I am a newbie studying Uniswap V3's github code. I came up with noDelegateCall.sol and I found out the way to prevent a contract to be delegatecalled from another cotract. As I tried to implement this, I caught up with the problem.
pragma solidity >0.8.0;
contract Receiver {
string greeting = "Hello";
address private immutable original;
event Greeting(string greeting, address original, address addressThis);
constructor() {
original = address(this);
}
function checkNotDelegateCall() private view {
require(address(this) == original);
}
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
function greet() external noDelegateCall {
emit Greeting(greeting, original, address(this));
}
}
contract Sender {
string greeting = "Hi";
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
}
}
If I call function delegatedGreeting, I expect the function to be reverted because variables original and address(this) differs. However, although it emits an empty event, it still doesn't reverts. Why does this happen?
When the low-level delegatecall reverts, it doesn't automatically revert the main transaction. Instead, it returns false as the first return value of the delegatecall() function.
So you need to check the return value (in your case bool success) and validate that.
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
require(success == true, "delegatecall failed");
}
I just got started with solidity, I have used truffle to compile and deploy the code to ganache, everything works as I expect, I can call the other functions in the code, but there are certain functions that only the owner can access, the code appears to use keccak256 to get back the address calling the function and determine if the caller address is allowed, I have tried to hash my eth address using this website:
https://emn178.github.io/online-tools/keccak_256.html
and then add the hash to the code before recompiling again, but calling the owner function still throws this error:
"Error: VM Exception while processing transaction: revert"
What am i doing wrong ?
Here's the code with the original hash.
modifier onlyOwner(){
address _customerAddress = msg.sender;
require(owners[keccak256(_customerAddress)]);
_;
}
// owners list
mapping(bytes32 => bool) public owners;
function PetShop()
public
{
// add owners here
owners[0x66e62cf7a807daaf3e42f7af3befe7b2416a79ba5348820245a69fe701f80eb4] = true;
}
/*---------- Owner ONLY FUNCTIONS ----------*/
function disableDogs()
onlyOwner()
public
{
onlyDogs = false;
}
/*-----replace owner ------*/
function setOwner(bytes32 _identifier, bool _status)
onlyOwner()
public
{
owners[_identifier] = _status;
}
/*-----set price for pet adoption----*/
function setAdoptionRequirement(uint256 _amountOfTokens)
onlyOwner()
public
{
AdoptionRequirement = _amountOfTokens;
}
The keccak256 implementation in Solidity stores data differently.
keccak256(...) returns (bytes32):
compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
Just use the function yourself when creating the contract:
function PetShop() public {
// add owners here
owners[keccak256(msg.sender)] = true;
}
as of now
// .encodePacked merges inputs together
owners[keccak256(abi.encodePacked(_text, _num, _addr))}=true
abi.encodePacked() , Solidity supports a non-standard packed mode where:
types shorter than 32 bytes are neither zero padded nor sign extended
dynamic types are encoded in-place and without the length.
array elements are padded, but still encoded in-place
So, as part of the bitdegree course on solidity I'm looking to create a modifier named onlyOwner and assign it to changePrice function. I must make sure the modifier allows function to be executed only if the sender's address matches the address of the owner. The sender's address can be obtained using msg.sender.
I have tried entering this to create the modifier but its not working for me and I'm not sure why. Any help/recommended code would be greatly appreciated!
pragma solidity ^0.4.17;
contract ModifiersTutorial {
address public owner;
uint256 public price = 0;
address public sender=msg.sender;
//
modifier onlyOwner(sender){
if (owner==sender);
}
//
// Use your modifier on the function below
function changePrice(uint256 _price) public onlyOwner {
price = _price;
}
function ModifiersTutorial () {
owner = msg.sender; // msg.sender in constructor equals to the address that created the contract
}
}
Your modifier code is incorrect. You need an underscore to proceed.
modifier onlyOwner(sender){
if (owner==sender) _; // Note the underscore
}
Also, for security reasons, you really should just use msg.sender instead of passing it in.
modifier onlyOwner() {
if (owner == msg.sender) _;
}
Not sure if it conflicts with the spec you've been given, but an alternative practice would be to require(owner == msg.sender) rather than use an if statement -- the former tells the user what happened, while the latter simply fails silently. This is what it could look like:
modifier onlyOwner(){
require(owner == msg.sender, "error-only-owner");
_;
}
pragma solidity ^0.4.17;
contract ModifiersTutorial {
address public owner;
uint256 public price = 0;
modifier onlyOwner(){
if( owner == msg.sender ) _;
}
function changePrice(uint256 _price) public onlyOwner{
price = _price;
}
function ModifiersTutorial () {
owner = msg.sender;
}
}
I'm trying to change the value of a variable in a contract that is in the blockchain. I've deducted its code and is something like this:
pragma solidity ^0.4.8;
contract Trial {
address public owner;
address public person;
uint initialEther;
function Trial(address _person) payable {
owner = msg.sender;
person = _person;
initialEther = msg.value;
}
modifier only_person() {
if (msg.sender!=person && tx.origin!=person) throw;
_;
}
function() payable {}
bytes4 public signature = bytes4(sha3("libraryFunction()"));
bool variableToBeChanged = false;
function libraryInvocation(address libraryAddress) only_person {
bool doSomething = libraryAddress.delegatecall(signature);
if (variableToBeChanged) {
.....
}
}
}
Suppose that I have the right signature of the library function, what I'm trying to do is to change the value of "variableToBeChanged" in order to execute the code inside the if.
Probably there is a way to create a library with a function with a proper name and inserting assembler code in some way to change the value of the variable. But it's like using an atomic bomb to kill an ant. I'm looking for the simpler way to do this.
I also know this contract is not safe, I'm trying to understand if this is possible and I want to understand how risky this can be for a contract.
Without a function changing the variable it is not possible. Once the contract code is deployed, it is final, no change is possible. You need to deploy a new contract.
You could control with your contract which wallet is allowed to call the function by checking the msg.sender attribute for a specific wallet address.
address owner = 0x2FD4...;
if(msg.sender != owner) throw;
//code afterwards)