sway icon indicating copy to clipboard operation
sway copied to clipboard

`transfer` doesn't work as expected with `forc` `0.48.1` and `fuels` `0.53.0`

Open haardikk21 opened this issue 2 years ago • 2 comments

Hey all,

Been playing with the nightly toolchain of fuelup for some projects we're building @LearnWeb3DAO because of a bug fix that was patched in that version and exists in beta-4.

I've noticed the transfer function from std::token::transfer doesn't work nicely for some reason.

Here is the relevant code along with a following explanation:

#[storage(read, write)]
    fn claim(stream_id: u64) {
        let sender = msg_sender().unwrap();

        let mut stream = storage.streams.get(stream_id).read();

        if stream.recipient != sender {
            revert(UNAUTHORIZED);
        }

        let current_block = height();
        let block_delta = stream.get_blocks_delta(current_block);
        let total_claimable_until_now = stream.amount_per_block * block_delta.as_u64();
        let claimable_now = total_claimable_until_now - stream.claimed;

        stream.claimed = total_claimable_until_now;
        storage.streams.insert(stream_id, stream);

       // Relevant parts 
        log(stream.recipient);
        log(stream.asset_id);
        log(claimable_now);
        transfer(stream.recipient, stream.asset_id, claimable_now);
    }

transfer in the above code is std::token::transfer

In my test harness, I'm doing:

contract_instance
        .with_account(recipient_wallet.clone())
        .unwrap()
        .methods()
        .claim(stream_id)
        .call()
        .await
        .expect("Failed to claim");

where stream_id is a valid u64.

This results in a panic:

Failed to claim: RevertTransactionError { reason: "failed transfer to address.", revert_id: 18446744073709486081, receipts: [Call { id: 0000000000000000000000000000000000000000000000000000000000000000, to: 67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924, amount: 0, asset_id: 0000000000000000000000000000000000000000000000000000000000000000, gas: 2571, param1: 2892928773, param2: 0, pc: 11632, is: 11632 }, LogData { id: 67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924, ra: 0, rb: 0, ptr: 33208, len: 40, digest: 6905085070841ddc8a266f5c2ae6b0cfb8a62a241f1befeaaac9df3340c3f094, pc: 14168, is: 11632, data: Some(000000000000000009c0b2d1a4...) }, LogData { id: 67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924, ra: 0, rb: 1, ptr: 33248, len: 32, digest: 66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925, pc: 14196, is: 11632, data: Some(00000000000000000000000000...) }, Log { id: 67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924, ra: 30, rb: 2, rc: 0, rd: 0, pc: 14204, is: 11632 }, Revert { id: 67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924, ra: 18446744073709486081, pc: 14428, is: 11632 }, ScriptResult { result: Revert, gas_used: 2679 }] }

Or, a prettified JSON version:

{
    "reason": "failed transfer to address.",
    "revert_id": "18446744073709486081",
    "receipts": [
      {
        "id": "0000000000000000000000000000000000000000000000000000000000000000",
        "to": "67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924",
        "amount": 0,
        "asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
        "gas": 2571,
        "param1": 2892928773,
        "param2": 0,
        "pc": 11632,
        "is": 11632
      },
      {
        "id": "67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924",
        "ra": 0,
        "rb": 0,
        "ptr": 33208,
        "len": 40,
        "digest": "6905085070841ddc8a266f5c2ae6b0cfb8a62a241f1befeaaac9df3340c3f094",
        "pc": 14168,
        "is": 11632,
        "data": "Some(000000000000000009c0b2d1a4...)"
      },
      {
        "id": "67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924",
        "ra": 0,
        "rb": 1,
        "ptr": 33248,
        "len": 32,
        "digest": "66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925",
        "pc": 14196,
        "is": 11632,
        "data": "Some(00000000000000000000000000...)"
      },
      {
        "id": "67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924",
        "ra": 30,
        "rb": 2,
        "rc": 0,
        "rd": 0,
        "pc": 14204,
        "is": 11632
      },
      {
        "id": "67433f736acb6a5ee7985f34a2b0908231678c08791deb3e08b09258128f0924",
        "ra": 18446744073709486000,
        "pc": 14428,
        "is": 11632
      },
      {
        "result": "Revert",
        "gas_used": 2679
      }
    ]
  }

As you can see in the first log receipt for Call, it says amount: 0

The transfer docs are clear that it will fail if amount = 0 - this is fine

The weird part is, claimable_now (the amount) isn't actually zero.

Looking at the later logs where I logged the 3 variable inputs to transfer, we can see in the last one ra: 30 which represents the value of claimable_now RIGHT BEFORE the transfer call

Something somewhere is going wrong and causing the transfer call to think I'm passing in an amount of zero, when I'm actually passing it an amount of 30.

haardikk21 avatar Dec 12 '23 18:12 haardikk21

Could you add .append_variable_outputs(1) to your sdk harness call so that it looks like this and try again?

contract_instance
        .with_account(recipient_wallet.clone())
        .unwrap()
        .methods()
        .claim(stream_id)
        .append_variable_outputs(1)
        .call()
        .await
        .expect("Failed to claim");

bitzoic avatar Jan 15 '24 07:01 bitzoic

Could you add .append_variable_outputs(1) to your sdk harness call so that it looks like this and try again?

contract_instance
        .with_account(recipient_wallet.clone())
        .unwrap()
        .methods()
        .claim(stream_id)
        .append_variable_outputs(1)
        .call()
        .await
        .expect("Failed to claim");

This fixed it - can you explain what happened here? How can the docs be improved to make this clear?

haardikk21 avatar Jan 30 '24 16:01 haardikk21

Could you add .append_variable_outputs(1) to your sdk harness call so that it looks like this and try again?

contract_instance
        .with_account(recipient_wallet.clone())
        .unwrap()
        .methods()
        .claim(stream_id)
        .append_variable_outputs(1)
        .call()
        .await
        .expect("Failed to claim");

This fixed it - can you explain what happened here? How can the docs be improved to make this clear?

This is part of the Rust SDK. Documentation on this can be found here: https://rust.fuel.network/v0.55.0/calling-contracts/variable-outputs.html

bitzoic avatar Feb 05 '24 06:02 bitzoic