neo_solidity/neo/
method_token.rs

1/// Method token for cross-contract calls in NEF format.
2///
3/// Method tokens are used to optimize calls to other contracts by caching
4/// the target contract hash and method information in the NEF header.
5#[derive(Debug, Clone)]
6pub struct MethodToken {
7    /// Target contract hash (20 bytes, Script Hash)
8    pub hash: [u8; 20],
9    /// Method name to call
10    pub method: String,
11    /// Number of parameters the method accepts
12    pub parameters_count: u16,
13    /// Whether the method returns a value
14    pub has_return_value: bool,
15    /// Call flags (Neo N3 `CallFlags` bitmask; `All` = 0x0F)
16    pub call_flags: u8,
17}
18
19impl MethodToken {
20    /// Create a new method token
21    pub fn new(hash: [u8; 20], method: &str, params: u16, has_return: bool, flags: u8) -> Self {
22        Self {
23            hash,
24            method: method.to_string(),
25            parameters_count: params,
26            has_return_value: has_return,
27            call_flags: flags,
28        }
29    }
30
31    /// Get the contract hash as hex string
32    pub fn hash_hex(&self) -> String {
33        hex::encode(self.hash)
34    }
35
36    /// Check if call flags allow state changes
37    pub fn allows_state_changes(&self) -> bool {
38        self.call_flags & 0x01 != 0
39    }
40
41    /// Serialize the method token to bytes
42    fn serialize(&self, buffer: &mut Vec<u8>) {
43        // Contract hash (20 bytes)
44        buffer.extend_from_slice(&self.hash);
45
46        // Method name (length-prefixed string, max 32 bytes per Neo spec)
47        let bytes = self.method.as_bytes();
48        assert!(
49            bytes.len() <= MAX_TOKEN_METHOD_LENGTH,
50            "method token '{}' exceeds {MAX_TOKEN_METHOD_LENGTH} bytes",
51            self.method
52        );
53        write_varbytes(buffer, bytes);
54
55        // Parameters count (2 bytes, little-endian)
56        buffer.extend_from_slice(&self.parameters_count.to_le_bytes());
57
58        // Has return value (1 byte)
59        buffer.push(if self.has_return_value { 1 } else { 0 });
60
61        // Call flags (1 byte)
62        buffer.push(self.call_flags);
63    }
64}