2

I have two contracts.

Contract A is an ERC20 token with initial_supply all owned by the contract itself.

And Contract B which exposes a deposit method.

When a user sends a transaction to ContractB.deposit() I want it to:

  1. Send Contract A coins to contract B (from contract B i.e, contract B needs to request the coins from contract A to B)<- not sure how to do
  2. Send Contract A coins which are now stored in contract B to msg.sender <- not sure how to do

How can I achieve this? My own attempts have largely failed.

5
  • Hi Christian! Welcome to Ethereum Stackexchange! Who owns the token in 1? To make contract X request something from Y it will have to call a function from Y, then contract Y can send the anwer to X. If you provide more details about 1 and 2 I'll try to make some code to explain in detail.
    – Ismael
    Commented Nov 16, 2021 at 12:27
  • Hi Ismael! Thanks for the warm welcome :) I own token contract 1 (I initialised it) and I also own token contract 2 - I hope that answers your question Commented Nov 16, 2021 at 14:07
  • The question was who owns the tokens that B wants to transfer. B only has access to its own tokens. The question isn't about contract's ownership, but who has the minted tokens.
    – Ismael
    Commented Nov 16, 2021 at 16:41
  • The contract itself owns the coins (inital_supply = address(self)) Commented Nov 16, 2021 at 17:24
  • Take a look at the answer to this question ethereum.stackexchange.com/questions/46457/…, depending on who owns the tokens either use transfer or approve+transferFrom.
    – Ismael
    Commented Nov 16, 2021 at 21:29

2 Answers 2

0

Use delegateCall in contract B to execute contract A. This executes contract A code with contract B storage.

Not sure what deposit does, it seems more like a withdraw to me.

Nonetheless, contract B needs to have enough allowance from contract A then you can call a delegateCall with transfer from contract B to execute transfer from contact A, and this sends the tokens to msg.sender

This is basically the same as when EOA with enough allowance calls a transfer from the contract to itself, the only difference is that you are using another contract instead.

Read these to understand DelegateCall;

https://solidity-by-example.org/delegatecall/ https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c

Edit after a long time:

  1. On the ERC-20 constructor give max allowance to contract B
  2. On deposit do a transferFrom(A, address(this), amount) now B has A amount tokens
  3. Then do transferFrom(address(this), msg.sender, amount) now B uses the amount of tokens that it just got from A and send it to the msg.sender

PD: Its kinda pointless to sent tokens from A to B and then B to sender. You could simple to a transferFrom(A, msg.sender, amount). B must have max allowance on itself to send the second txn

2
  • This sounds precisely like what I need - only 'tricky' thing is that I'm coding this in Vyper and I dont see support for DelegateCall - any ideas how to acheive this in Vyper ? Commented Nov 15, 2021 at 10:08
  • This solution won't work, because it requires contract A storage layout to be compatible with contract B (declare data variables in the same order, inherit the same contract in the same order, etc), also contract A storage will never be used, everything will be stored in contract B.
    – Ismael
    Commented Nov 16, 2021 at 12:13
0

A year older and wiser...

Contract A has an ERC20 balance (and might be an ERC20 contract itself with ERC20(coinA).balanceOf(self) a positive number.

Contract B has no coinA balance but requires a coinA balance.

ContractA has an init method which ERC20(coinA).approve(coinB,MAX_UINT256) this allows contractB to withdraw all of coinA's balance (you could limit this by reducing the MAX_UINT256 to an appropriate value).

ContractB then has a method eg

def pull_coin(_amount: uint256)->uint256: 
   assert msg.sender == self.admin, "only admin"
   ERC20(coinA).transferFrom(contractA,self,_amount)
   ERC20(coinA).transfer(msg.sender,_amount)
   return _amount

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.