1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use cfx_types::{Address, AddressSpaceUtil, AddressWithSpace, Space};
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AddressPocket {
    Balance(AddressWithSpace),
    StakingBalance(Address),
    StorageCollateral(Address),
    SponsorBalanceForGas(Address),
    SponsorBalanceForStorage(Address),
    MintBurn,
    GasPayment,
}

impl AddressPocket {
    pub fn inner_address(&self) -> Option<&Address> {
        use AddressPocket::*;
        match self {
            Balance(AddressWithSpace { address: addr, .. })
            | StakingBalance(addr)
            | StorageCollateral(addr)
            | SponsorBalanceForGas(addr)
            | SponsorBalanceForStorage(addr) => Some(addr),
            MintBurn | GasPayment => None,
        }
    }

    pub fn inner_address_or_default(&self) -> Address {
        self.inner_address().cloned().unwrap_or(Address::zero())
    }

    pub fn pocket(&self) -> &'static str {
        use AddressPocket::*;
        match self {
            Balance(_) => "balance",
            StakingBalance(_) => "staking_balance",
            StorageCollateral(_) => "storage_collateral",
            SponsorBalanceForGas(_) => "sponsor_balance_for_gas",
            SponsorBalanceForStorage(_) => "sponsor_balance_for_collateral",
            MintBurn => "mint_or_burn",
            GasPayment => "gas_payment",
        }
    }

    pub fn space(&self) -> &'static str {
        use AddressPocket::*;
        match self {
            Balance(AddressWithSpace { space, .. }) => space.clone().into(),
            MintBurn | GasPayment => "none",
            _ => Space::Native.into(),
        }
    }

    fn type_number(&self) -> u8 {
        use AddressPocket::*;
        match self {
            Balance(AddressWithSpace {
                space: Space::Native,
                ..
            }) => 0,
            StakingBalance(_) => 1,
            StorageCollateral(_) => 2,
            SponsorBalanceForGas(_) => 3,
            SponsorBalanceForStorage(_) => 4,
            MintBurn => 5,
            GasPayment => 6,
            Balance(AddressWithSpace {
                space: Space::Ethereum,
                ..
            }) => 7,
        }
    }
}

impl Encodable for AddressPocket {
    fn rlp_append(&self, s: &mut RlpStream) {
        let maybe_address = self.inner_address();
        let type_number = self.type_number();
        if let Some(address) = maybe_address {
            s.begin_list(2);
            s.append(&type_number);
            s.append(address);
        } else {
            s.begin_list(1);
            s.append(&type_number);
        }
    }
}

impl Decodable for AddressPocket {
    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
        use AddressPocket::*;

        let type_number: u8 = rlp.val_at(0)?;
        match type_number {
            0 => rlp
                .val_at(1)
                .map(|addr: Address| Balance(addr.with_native_space())),
            1 => rlp.val_at(1).map(StakingBalance),
            2 => rlp.val_at(1).map(StorageCollateral),
            3 => rlp.val_at(1).map(SponsorBalanceForGas),
            4 => rlp.val_at(1).map(SponsorBalanceForStorage),
            5 => Ok(MintBurn),
            6 => Ok(GasPayment),
            7 => rlp
                .val_at(1)
                .map(|addr: Address| Balance(addr.with_evm_space())),
            _ => {
                Err(DecoderError::Custom("Invalid internal transfer address."))
            }
        }
    }
}