iota_types/stardust/
coin_kind.rs1use std::mem::size_of;
18
19use crate::{
20 balance::Balance,
21 gas_coin::GAS,
22 object::{ID_END_INDEX, Object},
23 stardust::output::{AliasOutput, BasicOutput, NftOutput},
24 timelock::timelock::TimeLock,
25};
26
27pub fn is_gas_coin_kind(object: &Object) -> bool {
29 let Some(struct_tag) = object.struct_tag() else {
30 return false;
31 };
32 struct_tag == AliasOutput::tag(GAS::type_tag())
33 || struct_tag == BasicOutput::tag(GAS::type_tag())
34 || struct_tag == NftOutput::tag(GAS::type_tag())
35 || struct_tag == TimeLock::<Balance>::type_(Balance::type_(GAS::type_tag()).into())
36 || object.is_gas_coin()
37}
38
39pub fn get_gas_balance_maybe(object: &Object) -> Option<Balance> {
43 if !is_gas_coin_kind(object) {
44 return None;
45 }
46 let inner = object.data.try_as_move()?;
47 bcs::from_bytes(&inner.contents()[ID_END_INDEX..][..size_of::<Balance>()]).ok()
48}
49
50#[cfg(test)]
51mod tests {
52 use iota_protocol_config::ProtocolConfig;
53
54 use crate::{
55 balance::Balance,
56 base_types::{IotaAddress, ObjectID, TxContext},
57 id::UID,
58 object::{Object, Owner},
59 stardust::{
60 coin_kind::{get_gas_balance_maybe, is_gas_coin_kind},
61 coin_type::CoinType,
62 output::{AliasOutput, BasicOutput, NftOutput},
63 },
64 timelock::timelock::{TimeLock, to_genesis_object},
65 };
66
67 fn nft_output(balance: u64, coin_type: CoinType) -> anyhow::Result<Object> {
68 let id = UID::new(ObjectID::random());
69 let balance = Balance::new(balance);
70 let output = NftOutput {
71 id,
72 balance,
73 native_tokens: Default::default(),
74 storage_deposit_return: Default::default(),
75 timelock: Default::default(),
76 expiration: Default::default(),
77 };
78 output.to_genesis_object(
79 IotaAddress::ZERO,
80 &ProtocolConfig::get_for_min_version(),
81 &TxContext::random_for_testing_only(),
82 1.into(),
83 coin_type,
84 )
85 }
86
87 #[test]
88 fn is_coin_kind_nft_output() {
89 let object = nft_output(100, CoinType::Iota).unwrap();
90 assert!(is_gas_coin_kind(&object));
91 }
92
93 #[test]
94 fn get_gas_balance_nft_output() {
95 let value = 100;
96 let object = nft_output(value, CoinType::Iota).unwrap();
97 let gas_coin_balance = get_gas_balance_maybe(&object).unwrap();
98 assert_eq!(gas_coin_balance.value(), value);
99 }
100
101 fn alias_output(balance: u64, coin_type: CoinType) -> anyhow::Result<Object> {
102 let id = UID::new(ObjectID::random());
103 let balance = Balance::new(balance);
104 let output = AliasOutput {
105 id,
106 balance,
107 native_tokens: Default::default(),
108 };
109 output.to_genesis_object(
110 Owner::AddressOwner(IotaAddress::ZERO),
111 &ProtocolConfig::get_for_min_version(),
112 &TxContext::random_for_testing_only(),
113 1.into(),
114 coin_type,
115 )
116 }
117
118 #[test]
119 fn is_coin_kind_alias_output() {
120 let object = alias_output(100, CoinType::Iota).unwrap();
121 assert!(is_gas_coin_kind(&object));
122 }
123
124 #[test]
125 fn get_gas_balance_alias_output() {
126 let value = 100;
127 let object = alias_output(value, CoinType::Iota).unwrap();
128 let gas_coin_balance = get_gas_balance_maybe(&object).unwrap();
129 assert_eq!(gas_coin_balance.value(), value);
130 }
131
132 fn basic_output(balance: u64, coin_type: CoinType) -> anyhow::Result<Object> {
133 let id = UID::new(ObjectID::random());
134 let balance = Balance::new(balance);
135 let output = BasicOutput {
136 id,
137 balance,
138 native_tokens: Default::default(),
139 storage_deposit_return: Default::default(),
140 timelock: Default::default(),
141 expiration: Default::default(),
142 metadata: Default::default(),
143 tag: Default::default(),
144 sender: Default::default(),
145 };
146 output.to_genesis_object(
147 IotaAddress::ZERO,
148 &ProtocolConfig::get_for_min_version(),
149 &TxContext::random_for_testing_only(),
150 1.into(),
151 &coin_type,
152 )
153 }
154
155 #[test]
156 fn is_coin_kind_basic_output() {
157 let object = basic_output(100, CoinType::Iota).unwrap();
158 assert!(is_gas_coin_kind(&object));
159 }
160
161 #[test]
162 fn get_gas_balance_basic_output() {
163 let value = 100;
164 let object = basic_output(value, CoinType::Iota).unwrap();
165 let gas_coin_balance = get_gas_balance_maybe(&object).unwrap();
166 assert_eq!(gas_coin_balance.value(), value);
167 }
168
169 fn timelock(balance: u64) -> anyhow::Result<Object> {
170 let id = UID::new(ObjectID::random());
171 let balance = Balance::new(balance);
172 let expiration_timestamp_ms = 10;
173 let label = None;
174
175 let timelock = TimeLock::new(id, balance, expiration_timestamp_ms, label);
176 Ok(to_genesis_object(
177 timelock,
178 IotaAddress::ZERO,
179 &ProtocolConfig::get_for_min_version(),
180 &TxContext::random_for_testing_only(),
181 1.into(),
182 )?)
183 }
184
185 #[test]
186 fn is_coin_kind_timelock() {
187 let object = timelock(100).unwrap();
188 assert!(is_gas_coin_kind(&object));
189 }
190
191 #[test]
192 fn get_gas_balance_timelock() {
193 let value = 100;
194 let object = timelock(value).unwrap();
195 let gas_coin_balance = get_gas_balance_maybe(&object).unwrap();
196 assert_eq!(gas_coin_balance.value(), value);
197 }
198}