The situation you've described is a common challenge when using factory or deployer contracts in combination with other contracts that rely on msg.sender
for initial setup, especially when the desired behavior is to assign ownership or mint tokens to the original caller.
Here's a breakdown of the problem and potential solutions:
- The Problem with
msg.sender
and Factory Contracts:
- When a contract (like Axelar's Constant Address Deployer) deploys another contract, the
msg.sender
in the deployed contract's constructor will be the address of the deployer contract, not the address of the account that called the deployer contract's function. - This is why, in the scenario you described, all the tokens go to the
ConstAddressDeployer
contract.
- Using
tx.origin
:
tx.origin
always refers to the original sender of the transaction, i.e., the externally owned account (EOA) that initiated the transaction.- While this would solve the problem in the scenario you described, using
tx.origin
is generally discouraged because it can introduce security vulnerabilities, especially in more complex dApps where malicious contracts can trick users into sending transactions.
- Potential Solutions:
a. Pass the Desired Address as a Constructor Argument:
- Modify the token contract to accept an address as a constructor argument. This address will be the recipient of the minted tokens or the owner of the contract.
- When the deployer contract deploys the token contract, it can pass the desired address (e.g.,
msg.sender
of the deployer contract) as an argument to the token contract's constructor.
b. Use a Setup Function:
- Instead of setting the owner or minting tokens in the constructor, have a separate public function in the token contract for this purpose. This function can only be called once and sets the owner or mints the tokens.
- After deploying the token contract using the deployer contract, call this setup function directly from the desired owner account.
c. Delegate Call Initialization:
- Use a delegate call from the deployer contract to the initialization function of the token contract. This way,
msg.sender
within the token contract will be the original caller, not the deployer contract. However, this approach is more complex and requires a deeper understanding of the Ethereum Virtual Machine (EVM) to implement safely.
- Recommendation:
- The first solution (passing the desired address as a constructor argument) is the most straightforward and is commonly used in practice. It provides clarity and avoids the pitfalls associated with
tx.origin
and the complexities of delegate calls.