0

I'm writing an ERC20 contract that would allow another ERC20 to be able to work with my contract, and am unsure how to get a specific address in the scenario given below.

Say my contract is CoinA, and someone else's contract is PartnerCoin. I'm proxied, and they may or may not be (in the scenario, I am already aware of if they are or aren't proxied, however). And say I'm using OpenZeppelin as my proxy. My coin's proxy contract address is 0x123 and their coin's contract (or proxy) address is 0x456. We can say that, if PartnerCoin is proxied, then their implementation address is 0x192.

Person, Bob, comes along and wants to transfer 10 of his PartnerCoin over to his friend, John. Bob's wallet address is 0x987 and John's wallet address is 0x654. PartnerCoin has a require on its transfer function that it must receive a specific response from a public function it can call from CoinA, otherwise it won't transfer. It calls the function, we'll call it SuperFunction, on CoinA and awaits a response.

I only want PartnerCoin to be able to call SuperFunction, at least for now, and I know what PartnerCoin's address is.

Within my implementation contract, say, 0x384, I believe it's the case that:

msg.sender would return 0x123, my own proxy, because my proxy is calling my implementation, correct?

_msgSender() would return 0x987, because they're the actual end user.

What would return 0x456, PartnerCoin's contract address, so that CoinA could check that it's indeed PartnerCoin that is calling SuperFunction, and not some other coin?

Thank you for the help!

1 Answers1

0

The OpenZeppelin _msgSender() (source) currently (OZ 4.x, Solc 0.8.x) returns the same value as the global variable msg.sender. The function exists for easier upgradability, if the msg.sender ever becomes deprecated (as already happened with its predecessor, tx.origin).

When the PartnerCoin calls your SuperFunction, it doesn't make a difference if they're calling your contract directly or through a proxy (that delegatecalls your contract). The msg.sender is always going to be the PartnerCoin

If the proxy only called (and not delegatecalled) your contract, then yes, the msg.sender would be the proxy. But that's not the case of the OpenZeppelin Proxy contract (source).

Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • So in my example, both msg.sender and _msgSender() would return 0x456, then? Or would they both return 0x987? Thanks for the help! – RatherPeachy Oct 04 '21 at 13:44
  • @RatherPeachy Both would return the `PartnerCoin` implementation (not proxy) address. Unfortunately I don't see this address in your question. – Petr Hejda Oct 04 '21 at 13:46
  • @RatherPeachy The 0x987 (Bob's address) would be `msg.sender` in your contract if Bob `call`ed `PartnerCoin` (doesn't matter if through a proxy or directly) and the `PartnerCoin`would `delegatecall`ed your contract. But then `PartnerCoin` would act as a proxy so your contract wouldn't have access to your contracts storage (it would use the storage of the proxy, in this case the `PartnerCoin`). – Petr Hejda Oct 04 '21 at 13:52
  • This makes a lot of sense! In case we need to reference the `PartnerCoin` implementation address again, let's call it 0x192 - I'll edit the original question with that information. It sounds like, then, if Bob (0x987) `call`ed `PartnerCoin`, but `PartnerCoin` then called `SuperFunction`, then the only way for `SuperFunction` to have both addresses, 0x192 and 0x987, would be for `PartnerCoin` to pass 0x987 along as a parameter. So then, for `SuperFunction`, `_msgSender()` (and `msg.sender`) would be 0x192, and this new parameter could be 0x987. Correct? – RatherPeachy Oct 04 '21 at 14:02
  • @RatherPeachy That's correct. – Petr Hejda Oct 04 '21 at 14:27