@@ -14,9 +14,10 @@ use sha2::{Digest, Sha256};
14
14
use std:: cell:: RefCell ;
15
15
16
16
use crate :: {
17
- account_balance_add, account_balance_get, account_balance_sub, get_timestamp_ns,
18
- ledger_add_reputation_change, slice_to_32_bytes_array, DccIdentity , TokenAmountE9s ,
19
- TransferError , LABEL_DC_TOKEN_TRANSFER , MINTING_ACCOUNT , MINTING_ACCOUNT_PRINCIPAL ,
17
+ account_balance_add, account_balance_get, account_balance_sub, amount_as_string,
18
+ get_pubkey_from_principal, get_timestamp_ns, ledger_add_reputation_change,
19
+ slice_to_32_bytes_array, DccIdentity , TokenAmountE9s , TransferError , LABEL_DC_TOKEN_TRANSFER ,
20
+ MINTING_ACCOUNT , MINTING_ACCOUNT_PRINCIPAL ,
20
21
} ;
21
22
22
23
thread_local ! {
@@ -63,34 +64,33 @@ pub fn ledger_funds_transfer(
63
64
64
65
pub fn charge_fees_to_account_and_bump_reputation (
65
66
ledger : & mut LedgerMap ,
66
- dcc_id_charge : & DccIdentity ,
67
- dcc_id_bump_reputation : & DccIdentity ,
67
+ dcc_id : & DccIdentity ,
68
68
amount_e9s : TokenAmountE9s ,
69
69
) -> Result < ( ) , String > {
70
70
if amount_e9s == 0 {
71
71
return Ok ( ( ) ) ;
72
72
}
73
- let balance_from_after =
74
- account_balance_get ( & dcc_id_charge . as_icrc_compatible_account ( ) ) - amount_e9s ;
73
+ let from_icrc1_account = dcc_id . as_icrc_compatible_account ( ) ;
74
+ let balance_from_before = account_balance_get ( & from_icrc1_account ) ;
75
75
match ledger_funds_transfer (
76
76
ledger,
77
77
// Burn 0 tokens, and transfer the entire amount_e9s to the fee accounts
78
78
FundsTransfer :: new (
79
- dcc_id_charge . as_icrc_compatible_account ( ) ,
79
+ from_icrc1_account ,
80
80
MINTING_ACCOUNT ,
81
81
amount_e9s. into ( ) ,
82
82
Some ( fees_sink_accounts ( ) ) ,
83
83
Some ( get_timestamp_ns ( ) ) ,
84
84
vec ! [ ] ,
85
85
0 ,
86
- balance_from_after ,
86
+ balance_from_before . saturating_sub ( amount_e9s ) ,
87
87
0 ,
88
88
) ,
89
89
) {
90
90
Ok ( _) => Ok ( ledger_add_reputation_change (
91
91
ledger,
92
- dcc_id_bump_reputation ,
93
- amount_e9s. min ( i64 :: MAX as TokenAmountE9s ) as i64 ,
92
+ dcc_id ,
93
+ amount_e9s as i64 ,
94
94
) ?) ,
95
95
Err ( e) => {
96
96
info ! ( "Failed to charge fees: {}" , e) ;
@@ -101,26 +101,26 @@ pub fn charge_fees_to_account_and_bump_reputation(
101
101
102
102
pub fn charge_fees_to_account_no_bump_reputation (
103
103
ledger : & mut LedgerMap ,
104
- dcc_identity : & DccIdentity ,
104
+ dcc_id_charge : & DccIdentity ,
105
105
amount_e9s : TokenAmountE9s ,
106
106
) -> Result < ( ) , String > {
107
107
if amount_e9s == 0 {
108
108
return Ok ( ( ) ) ;
109
109
}
110
- let balance_from_after =
111
- account_balance_get ( & dcc_identity . as_icrc_compatible_account ( ) ) - amount_e9s ;
110
+ let from_icrc1_account = dcc_id_charge . as_icrc_compatible_account ( ) ;
111
+ let balance_from_before = account_balance_get ( & from_icrc1_account ) ;
112
112
match ledger_funds_transfer (
113
113
ledger,
114
114
// Burn 0 tokens, and transfer the entire amount_e9s to the fee accounts
115
115
FundsTransfer :: new (
116
- dcc_identity . as_icrc_compatible_account ( ) ,
116
+ from_icrc1_account ,
117
117
MINTING_ACCOUNT ,
118
118
Some ( amount_e9s) ,
119
119
Some ( fees_sink_accounts ( ) ) ,
120
120
Some ( get_timestamp_ns ( ) ) ,
121
121
vec ! [ ] ,
122
122
0 ,
123
- balance_from_after ,
123
+ balance_from_before . saturating_sub ( amount_e9s ) ,
124
124
0 ,
125
125
) ,
126
126
) {
@@ -132,6 +132,78 @@ pub fn charge_fees_to_account_no_bump_reputation(
132
132
}
133
133
}
134
134
135
+ pub enum IncreaseReputation {
136
+ None ,
137
+ Sender ,
138
+ Recipient ,
139
+ }
140
+
141
+ pub fn do_funds_transfer (
142
+ ledger : & mut LedgerMap ,
143
+ from_dcc_id : & DccIdentity ,
144
+ to_icrc1_account : & IcrcCompatibleAccount ,
145
+ transfer_amount_e9s : TokenAmountE9s ,
146
+ fees_amount_e9s : TokenAmountE9s ,
147
+ memo : & [ u8 ] ,
148
+ increase_reputation : IncreaseReputation ,
149
+ ) -> Result < String , String > {
150
+ let from_icrc1_account = from_dcc_id. as_icrc_compatible_account ( ) ;
151
+
152
+ if transfer_amount_e9s == 0 {
153
+ return Ok ( "Nothing to transfer" . to_string ( ) ) ;
154
+ }
155
+ let balance_from_before = account_balance_get ( & from_icrc1_account) ;
156
+ let balance_to_before = account_balance_get ( to_icrc1_account) ;
157
+ if balance_from_before < transfer_amount_e9s + fees_amount_e9s {
158
+ return Err ( format ! (
159
+ "Not enough funds to transfer: {} < {} + {}" ,
160
+ balance_from_before, transfer_amount_e9s, fees_amount_e9s
161
+ ) ) ;
162
+ }
163
+ let balance_from_after = balance_from_before - transfer_amount_e9s - fees_amount_e9s;
164
+ match ledger_funds_transfer (
165
+ ledger,
166
+ FundsTransfer :: new (
167
+ from_icrc1_account. clone ( ) ,
168
+ to_icrc1_account. clone ( ) ,
169
+ Some ( fees_amount_e9s) ,
170
+ Some ( fees_sink_accounts ( ) ) ,
171
+ Some ( get_timestamp_ns ( ) ) ,
172
+ memo. to_vec ( ) ,
173
+ transfer_amount_e9s,
174
+ balance_from_after,
175
+ balance_to_before + transfer_amount_e9s,
176
+ ) ,
177
+ ) {
178
+ Ok ( _) => {
179
+ let response = format ! (
180
+ "Transferred {} tokens from {} \t to account {}, and charged fees {} tokens" ,
181
+ amount_as_string( transfer_amount_e9s) ,
182
+ from_icrc1_account,
183
+ to_icrc1_account,
184
+ amount_as_string( fees_amount_e9s)
185
+ ) ;
186
+ match increase_reputation {
187
+ IncreaseReputation :: None => ( ) ,
188
+ IncreaseReputation :: Sender => {
189
+ ledger_add_reputation_change ( ledger, from_dcc_id, fees_amount_e9s as i64 ) ?;
190
+ }
191
+ IncreaseReputation :: Recipient => {
192
+ let to_dcc_identity = to_icrc1_account
193
+ . to_dcc_identity ( )
194
+ . expect ( "Failed to get dcc identity from icrc1 account" ) ;
195
+ ledger_add_reputation_change ( ledger, & to_dcc_identity, fees_amount_e9s as i64 ) ?;
196
+ }
197
+ }
198
+ Ok ( response)
199
+ }
200
+ Err ( e) => {
201
+ info ! ( "Failed to charge fees: {}" , e) ;
202
+ Err ( e. to_string ( ) )
203
+ }
204
+ }
205
+ }
206
+
135
207
#[ derive( CandidType , Deserialize , Clone , Debug , PartialEq , Eq , Hash ) ]
136
208
pub struct IcrcCompatibleAccount {
137
209
pub owner : Principal ,
@@ -201,6 +273,14 @@ impl IcrcCompatibleAccount {
201
273
pub fn from_bytes ( bytes : & [ u8 ] ) -> Result < Self , std:: io:: Error > {
202
274
borsh:: from_slice ( bytes)
203
275
}
276
+
277
+ pub fn to_dcc_identity ( & self ) -> Option < DccIdentity > {
278
+ let owner_bytes = get_pubkey_from_principal ( self . owner ) ;
279
+ if owner_bytes. is_empty ( ) {
280
+ return None ;
281
+ }
282
+ DccIdentity :: new_verifying_from_bytes ( & owner_bytes) . ok ( )
283
+ }
204
284
}
205
285
206
286
impl From < & str > for IcrcCompatibleAccount {
0 commit comments