Contracts and contracts and user issues

I have a problem
I have two contracts at the moment
One contract is an AEX9 token contract
A contract is a contract that I write my own logic

The requirement is that the user replaces the AEX 9 token with AE, or can replace the AEX 9 token with AE
Now I realize that the AEX9 token can be replaced by AE, but when I change back to AE from the AEX9 token, I find there will be problems, because what the user calls is the contract for writing logic, and the contract for writing logic calls the CONTRACT for AEX9. In this way, the default transfer is to operate the AEX9 token in the contract instead of the user’s token.

   contract FungibleTokenInterface =

  record meta_info =
    { name : string
    , symbol : string
    , decimals : int }

  datatype event =
    Transfer(address, address, int)
  entrypoint aex9_extensions   : ()             => list(string)
  entrypoint meta_info         : ()             => meta_info
  entrypoint total_supply      : ()             => int
  entrypoint owner             : ()             => address
  entrypoint balances          : ()             => map(address, int)
  entrypoint balance           : (address)      => option(int)
  entrypoint transfer          : (address, int) => unit


payable contract BoxContract =

  record state = {
    token_address : address, 
    map_hamsters : map(string, string), 
    testvalue: int}
        
  stateful entrypoint init(token : FungibleTokenInterface) = {
    token_address = token.address,
    map_hamsters = {},
    testvalue = 42  }


  entrypoint getTokenBalance(token : FungibleTokenInterface)  = 
    token.balance(Call.caller)


  entrypoint getCallCaller()  = 
    Call.caller

  entrypoint getContractBalance() = 
    Contract.balance

  entrypoint getContractAddress() = 
    Contract.address

  payable stateful entrypoint buy(token : FungibleTokenInterface) =
    Chain.spend(Contract.address, Call.value)
    token.transfer(Call.caller , Call.value)


  stateful entrypoint sell(token : FungibleTokenInterface , number : int) =
    switch(token.balance(Call.caller))
      Some(balance) =>
        require(balance > number, "BOX_INSUFFICIENT_BALANCE")
      None => abort("BALANCE_ACCOUNT_NOT_EXISTENT")

    //The problem code is here, I want to deduct the user AEX9 token
    token.transfer(Contract.address , number)
    Chain.spend(Call.caller, number)


  entrypoint getBalances(token : FungibleTokenInterface)  = 
    token.balances()

when an amound is passed with the call it is already owned by the contract, this line is useless.

is this intended to transfer the exact amount that the user provided in AE in Token value?


when you call the token.transfer like this you access the tokens owned by the contract. You can’t access user tokens like this. To build functionallity like this you will need to make use of allowances. Here is an example how we do that in superhero: https://github.com/aeternity/tipping-contract/blob/29bb58da3bf23d92820749ec7396b0c140521cf0/contracts/v2/Tipping_v2.aes#L143-L144

This will only work if the user first created an allowance for that contract to access the tokens.

Thank you for your reply
In this line of code I see that before I can execute this line I need to build an extensible AEX9 to create token
Then make the call, but the call prompted an error

token.transfer_allowance(Call.caller, Contract.address, token_amount)

I saw you say : This will only work if the user first created an allowance for that contract to access the tokens.

But how do you get user permission? Do you have sample code

The goal it for the contract to transfer the users tokens, right?

  1. the user needs to call create_allowance or change_allowance on the contract, e.g. like this https://github.com/aeternity/superhero-ui/blob/98d07eeb4e34a1a0a367955dc2f01e593b340bd7/src/utils/aeternity.js#L111-L128
  2. the contract can take the allowance to his account using transfer_allowance or directly transfer it to any other account

if the allowance is not created or to small in size the call will abort, you can see nice error messages if you try to dry-run these calls.

Ok, I think I should know about the protocols of AEX9 extension. I will study them first, and I will bother you if I have any questions. Thank you

Sure, let me know if you have any questions, this should fairly well explain everything you may need. https://github.com/mradkov/aeternity-fungible-token

AEX-9 is the implementation of a minimum viable fungible token, that shares a lot of similarities with ERC-20, e.g. the allowance methodology is the same.