fuel_core_chain_config/
fee_collection_contract.rs

1use fuel_core_types::{
2    fuel_asm::{
3        op,
4        GTFArgs,
5        Instruction,
6        RegId,
7    },
8    fuel_tx::{
9        Address,
10        AssetId,
11    },
12};
13
14/// Generates the bytecode for the fee collection contract.
15/// The contract expects `AssetId` and `output_index` as a first elements in `script_data`.
16pub fn generate(address: Address) -> Vec<u8> {
17    let start_jump = vec![
18        // Jump over the embedded address, which is placed immediately after the jump
19        op::ji((1 + (Address::LEN / Instruction::SIZE)).try_into().unwrap()),
20    ];
21
22    let asset_id_register = 0x10;
23    let balance_register = 0x11;
24    let contract_id_register = 0x12;
25    let output_index_register = 0x13;
26    let recipient_id_register = 0x14;
27    let body = vec![
28        // Load pointer to AssetId
29        op::gtf_args(asset_id_register, 0x00, GTFArgs::ScriptData),
30        // Load output index
31        op::addi(
32            output_index_register,
33            asset_id_register,
34            u16::try_from(AssetId::LEN).expect("The size is 32"),
35        ),
36        op::lw(output_index_register, output_index_register, 0),
37        // Gets pointer to the contract id
38        op::move_(contract_id_register, RegId::FP),
39        // Get the balance of asset ID in the contract
40        op::bal(balance_register, asset_id_register, contract_id_register),
41        // If balance == 0, return early
42        op::jnzf(balance_register, RegId::ZERO, 1),
43        op::ret(RegId::ONE),
44        // Pointer to the recipient address
45        op::addi(
46            recipient_id_register,
47            RegId::IS,
48            Instruction::SIZE.try_into().unwrap(),
49        ),
50        // Perform the transfer
51        op::tro(
52            recipient_id_register,
53            output_index_register,
54            balance_register,
55            asset_id_register,
56        ),
57        // Return
58        op::ret(RegId::ONE),
59    ];
60
61    let mut asm_bytes: Vec<u8> = start_jump.into_iter().collect();
62    asm_bytes.extend_from_slice(address.as_slice()); // Embed the address
63    let body: Vec<u8> = body.into_iter().collect();
64    asm_bytes.extend(body.as_slice());
65
66    asm_bytes
67}