Contract transfer problem

Hello, everyone
Looking at the documentation, we know that this is the method a user can use to transfer token to a contract address

Chain.spend(Contract.address, Call.value)

How do You send the token above the contract.Address to the user?

Any examples?? Thank you very much

1 Like

@erik.chain @ae-omar @philipp.chain

I’m happy to try to help, but I fail to understand the question…

Chain.spend(addr, ntokens) will spend ntokens from the contract to addr - there isn’t much more to explain?

2 Likes

The Chain.spend(addr, ntokens) will take from the function caller(Call.caller) wallet to send to addr. The question now is how does the contract send tokens from the Contract.Address to the function caller

Eh, no, it will most definitely not take/spend/transfer tokens from Call.caller - the contract can only spend tokens that belong to the contract itself…

If you think about it, it would be horribly insecure otherwise, any contract call you make could potentially spend all your tokens :see_no_evil:

If you want the contract to spend all your tokens you have to pass them to the contract in the contract call (the amount field in the ContractCallTx).

2 Likes

To explain better let me use an example of a trading system where Buy means trading Fiat to AE and Sell means trading AE to Fiat.

Sell
At this time, the Chain.spend method transfers token from the Callers address after confirmation to the stipulated address then keeps the record so the admin can send the equivalent Fiat to the user.

Buy
Then for Buy, the caller sends Fiat to get the equivalent in AE right? So how does one achieve this goal after the caller has sent the equivalent Fiat?

@Baixin.chain I hope I interpreted your question well.

It doesn’t matter what the use case is Chain.spend only takes two arguments, the account that receives the tokens, and the number of tokens to move.

To move tokens from account A to account B using contract C, account A first have to give those tokens to the contract C and then contract C can Chain.spend(B, …) - when doing a contract call you can attach tokens to the call, and likewise when you are doing a remote contract call inside a contract.

2 Likes

Thanks for the clarification

Hello @Baixin.chain, in other to backup @hanssv.chain explanation of the Chain.spend function, I created a simple contract and hope it helps. Find contract on AEStudio at AE Studio or use the below code snippet:

payable contract TestChainSpend =

    record config = {
        contract_address : address,
        contract_balance : int,
        caller_address : address,
        caller_balance : int}

    record buy = {
        buy_ref : hash,
        buy_fait : int,
        buy_value : int }

    record sell = {
        sell_ref : hash,
        sell_fait : int,
        sell_value : int }

    record state = {
        buys : map(hash, buy), 
        sells: map(hash, sell) }

    stateful entrypoint init() = {
        buys = {},
        sells = {} }
    
    public entrypoint get_config() =
        let config = {
            contract_address = Contract.address, 
            contract_balance = Chain.balance(Contract.address), 
            caller_address = Call.caller,
            caller_balance = Chain.balance(Call.caller)}

        config

    payable public stateful entrypoint sell_ae(sell_name : string) =
        let sell_tran_ref = String.sha3(sell_name)
        let fait_value = (Call.value / 1000000000000000000) * 100
        
        Chain.spend(Contract.address, Call.value)

        let new_sell = {sell_ref = sell_tran_ref, sell_fait = fait_value, sell_value = Call.value}

        put(state{sells[sell_tran_ref] = new_sell})

        new_sell

    payable public stateful entrypoint buy_ae(buy_name : string, fiat_amount : int) =
        let buy_tran_ref = String.sha3(buy_name)
        let ae_value = (fiat_amount / 100) * 1000000000000000000
        
        Chain.spend(Call.caller, ae_value)

        let new_buy = {buy_ref = buy_tran_ref, buy_fait = fiat_amount, buy_value = ae_value}

        put(state{buys[buy_tran_ref] = new_buy})

        new_buy

Note

  1. when calling the sell_ae function, make sure the Call.value is an AE value and not aettos or the rest
  2. When calling the 'buy_ae` function, make sure the fiat amount is greater than 100 and less than or equals to the balance on the Contract.address when divided by 1000000000000000000 and multiplied with 100.

Thanks @hanssv.chain for the knowledge shared.

Regards.

Thank you for solving my problem

2 Likes

Out of context, but:

You can simplify this:

To this:

    entrypoint get_config() : config = { 
        contract_address = Contract.address,
        contract_balance = Chain.balance(Contract.address),
        caller_address = Call.caller,
        caller_balance = Chain.balance(Call.caller) }
2 Likes

Thanks @bruteforce.chain

1 Like