ckb_sdk/transaction/handler/
typeid.rs

1use ckb_hash::new_blake2b;
2use ckb_types::{
3    packed::{Bytes, CellInput},
4    prelude::*,
5};
6
7use crate::{
8    core::TransactionBuilder, tx_builder::TxBuilderError, NetworkInfo, ScriptGroup, ScriptId,
9};
10
11use super::{HandlerContext, ScriptHandler};
12
13/// Type ID script handler, it will setup the [Type ID](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#type-id) script's args automatically.
14pub struct TypeIdHandler;
15
16pub struct TypeIdContext;
17
18impl HandlerContext for TypeIdContext {}
19#[cfg_attr(target_arch="wasm32", async_trait::async_trait(?Send))]
20#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
21impl ScriptHandler for TypeIdHandler {
22    fn build_transaction(
23        &self,
24        tx_builder: &mut TransactionBuilder,
25        script_group: &mut ScriptGroup,
26        context: &dyn HandlerContext,
27    ) -> Result<bool, TxBuilderError> {
28        if context.as_any().is::<TypeIdContext>()
29            && ScriptId::from(&script_group.script).is_type_id()
30            && script_group.input_indices.is_empty()
31            && script_group.output_indices.len() == 1
32        {
33            let input = tx_builder.get_inputs().first().unwrap();
34            let index = *script_group.output_indices.last().unwrap();
35            let args: Bytes = calculate_type_id(input, index as u64).to_vec().pack();
36            let output = tx_builder.get_outputs().get(index).unwrap().clone();
37            let output_type_script = output
38                .type_()
39                .to_opt()
40                .unwrap()
41                .as_builder()
42                .args(args)
43                .build();
44            let updated_output = output
45                .as_builder()
46                .type_(Some(output_type_script.clone()).pack())
47                .build();
48            tx_builder.set_output(index, updated_output);
49            script_group.script = output_type_script;
50            return Ok(true);
51        }
52        Ok(false)
53    }
54    #[cfg(not(target_arch = "wasm32"))]
55    fn init(&mut self, _network: &NetworkInfo) -> Result<(), TxBuilderError> {
56        Ok(())
57    }
58    async fn init_async(&mut self, _network: &NetworkInfo) -> Result<(), TxBuilderError> {
59        Ok(())
60    }
61}
62
63fn calculate_type_id(first_cell_input: &CellInput, output_index: u64) -> [u8; 32] {
64    let mut blake2b = new_blake2b();
65    blake2b.update(first_cell_input.as_slice());
66    blake2b.update(&output_index.to_le_bytes());
67    let mut ret = [0u8; 32];
68    blake2b.finalize(&mut ret);
69    ret
70}