I recently started development on a personal project, and one of the suggested methods to achieve what i want was using delegatecall. Essentially I have a main contract that the user interacts with and this main contract will using the implementations of other contracts. From what I read, delegatecall will call the target contract in the context of the calling contract, meaning it will retain the msg.sender/value of the original transaction and any changes made to storage will be in the context of the calling contract. For instance, I have the following code.
contract MainContract{
address public otherContract;
constructor (address _otherContract){
otherContract = _otherContract;
}
function registerUser(string memory _username) external {
(bool success,) = otherContract.delegatecall(
abi.encodeWithSignature("createUser(string)", _username)
);
require(success, "createUser failed");
}
}
Before i used delegatecall, i was directly calling the function as such OtherContract(otherContract).createUser(_username); and on my test file ran successfully other than the fact that the owner of account wasn't the EOA that originally started the transaction. Below is the function being called in OtherContract(Other contract inherits some events/enums from Activity). Note, I have tested the implementation contracts individually and they work as intended, only when I try to call the functions from a different contract is where I have issues:
contract OtherContract is Activity{
struct User{
address user;
string name;
bool userCreated;
Status status;
uint256 creationDate;
}
mapping(address => User) internal users;
uint256 public totalUsers = 0;
function createUser(string memory _name) external{
require(!users[msg.sender].userCreated, "Address already in use by active user!");
users[msg.sender] = User(msg.sender, _name, true, Status.Online, block.timestamp);
totalUsers++;
emit LogActivity(msg.sender, ActivityType.User, string.concat("New user created ", _name), block.timestamp);
}
}
After running the update MainContract not only is the user not being successfully created, but the event is being logged 4 times. From what I understand there are reentry issues when using delegatecall so having a modifier to prevent this was suggested. Another suggestion was to add another parameter for address to pass the EOAs address, but seeing as I have other functions and contracts that rely on msg.sender, I would like to avoid that.
Any suggestions on what I should do? Also is my understanding of delegatecall correct?