1use crate::SUI_FRAMEWORK_ADDRESS;
5use crate::error::{ExecutionError, ExecutionErrorKind};
6use crate::sui_serde::BigInt;
7use crate::sui_serde::Readable;
8use move_core_types::account_address::AccountAddress;
9use move_core_types::annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout};
10use move_core_types::ident_str;
11use move_core_types::identifier::IdentStr;
12use move_core_types::language_storage::{StructTag, TypeTag};
13use schemars::JsonSchema;
14use serde::Deserialize;
15use serde::Serialize;
16use serde_with::serde_as;
17
18pub const SUI_MODULE_NAME: &IdentStr = ident_str!("sui");
19pub const BALANCE_MODULE_NAME: &IdentStr = ident_str!("balance");
20pub const BALANCE_STRUCT_NAME: &IdentStr = ident_str!("Balance");
21pub const RESOLVED_BALANCE_STRUCT: (&AccountAddress, &IdentStr, &IdentStr) = (
22 &SUI_FRAMEWORK_ADDRESS,
23 BALANCE_MODULE_NAME,
24 BALANCE_STRUCT_NAME,
25);
26pub const BALANCE_CREATE_REWARDS_FUNCTION_NAME: &IdentStr = ident_str!("create_staking_rewards");
27pub const BALANCE_DESTROY_REBATES_FUNCTION_NAME: &IdentStr = ident_str!("destroy_storage_rebates");
28
29pub const BALANCE_REDEEM_FUNDS_FUNCTION_NAME: &IdentStr = ident_str!("redeem_funds");
30pub const BALANCE_SEND_FUNDS_FUNCTION_NAME: &IdentStr = ident_str!("send_funds");
31
32#[serde_as]
33#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)]
34pub struct Supply {
35 #[schemars(with = "BigInt<u64>")]
36 #[serde_as(as = "Readable<BigInt<u64>, _>")]
37 pub value: u64,
38}
39
40#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)]
41pub struct Balance {
42 value: u64,
43}
44
45impl Balance {
46 pub fn new(value: u64) -> Self {
47 Self { value }
48 }
49
50 pub fn type_(type_param: TypeTag) -> StructTag {
51 StructTag {
52 address: SUI_FRAMEWORK_ADDRESS,
53 module: BALANCE_MODULE_NAME.to_owned(),
54 name: BALANCE_STRUCT_NAME.to_owned(),
55 type_params: vec![type_param],
56 }
57 }
58
59 pub fn type_tag(type_param: TypeTag) -> TypeTag {
60 TypeTag::Struct(Box::new(Self::type_(type_param)))
61 }
62
63 pub fn is_balance(s: &StructTag) -> bool {
64 s.address == SUI_FRAMEWORK_ADDRESS
65 && s.module.as_ident_str() == BALANCE_MODULE_NAME
66 && s.name.as_ident_str() == BALANCE_STRUCT_NAME
67 && s.type_params.len() == 1
68 }
69
70 pub fn is_balance_type(type_param: &TypeTag) -> bool {
71 if let TypeTag::Struct(struct_tag) = type_param {
72 Self::is_balance(struct_tag)
73 } else {
74 false
75 }
76 }
77
78 pub fn maybe_get_balance_type_param(ty: &TypeTag) -> Option<TypeTag> {
80 if let TypeTag::Struct(struct_tag) = ty
81 && Self::is_balance(struct_tag)
82 {
83 assert_eq!(struct_tag.type_params.len(), 1);
84 return Some(struct_tag.type_params[0].clone());
85 }
86 None
87 }
88
89 pub fn withdraw(&mut self, amount: u64) -> Result<(), ExecutionError> {
90 fp_ensure!(
91 self.value >= amount,
92 ExecutionError::new_with_source(
93 ExecutionErrorKind::InsufficientCoinBalance,
94 format!("balance: {} required: {}", self.value, amount)
95 )
96 );
97 self.value -= amount;
98 Ok(())
99 }
100
101 pub fn deposit_for_safe_mode(&mut self, amount: u64) {
102 self.value += amount;
103 }
104
105 pub fn value(&self) -> u64 {
106 self.value
107 }
108
109 pub fn to_bcs_bytes(&self) -> Vec<u8> {
110 bcs::to_bytes(&self).unwrap()
111 }
112
113 pub fn layout(type_param: TypeTag) -> MoveStructLayout {
114 MoveStructLayout {
115 type_: Self::type_(type_param),
116 fields: vec![MoveFieldLayout::new(
117 ident_str!("value").to_owned(),
118 MoveTypeLayout::U64,
119 )],
120 }
121 }
122
123 pub fn is_balance_layout(struct_layout: &MoveStructLayout) -> bool {
125 let ty = &struct_layout.type_;
126
127 if !Self::is_balance(ty) {
128 return false;
129 }
130
131 if ty.type_params.len() != 1 {
132 return false;
133 }
134
135 if struct_layout.fields.len() != 1 {
136 return false;
137 }
138
139 let Some(field) = struct_layout.fields.first() else {
140 return false;
141 };
142
143 if field.name.as_str() != "value" {
144 return false;
145 }
146
147 if !matches!(field.layout, MoveTypeLayout::U64) {
148 return false;
149 }
150
151 true
152 }
153}