@@ -184,47 +184,7 @@ void TokensMaster::refreshTokenState(const csdb::Address& token, const std::stri
184184 auto & t = tokens_[token];
185185 t.name = name;
186186 t.symbol = symbol;
187- t.totalSupply = totalSupply;
188-
189- // balance
190- if (checkBalance) {
191- executor::ExecuteByteCodeMultipleResult result;
192- if (byteCodeObjects.empty ())
193- return ;
194-
195- executor::SmartContractBinary smartContractBinary;
196- smartContractBinary.contractAddress = addr;
197- smartContractBinary.object .byteCodeObjects = byteCodeObjects;
198- smartContractBinary.object .instance = newState;
199- smartContractBinary.stateCanModify = 0 ;
200-
201- std::vector<csdb::Address> holders;
202- holders.reserve (t.holders .size ());
203- for (auto & h : t.holders )
204- holders.push_back (h.first );
205-
206- std::vector<std::vector<general::Variant>> holderKeysParams;
207- holderKeysParams.reserve (holders.size ());
208- for (auto & h : holders) {
209- general::Variant var;
210- auto key = h.public_key ();
211- var.__set_v_string (EncodeBase58 (cs::Bytes (key.begin (), key.end ())));
212- holderKeysParams.push_back (std::vector<general::Variant>(1 , var));
213- }
214-
215- api_->getExecutor ().executeByteCodeMultiple (result, dpAddr, smartContractBinary, " balanceOf" , holderKeysParams, 100 , executor::Executor::kUseLastSequence );
216-
217- ++t.realHoldersCount = 0 ;
218- if (!result.status .code && (result.results .size () == holders.size ())) {
219- for (uint32_t i = 0 ; i < holders.size (); ++i) {
220- const auto & res = result.results [i];
221- if (!res.status .code ) {
222- t.holders [holders[i]].balance = tryExtractAmount (getVariantAs<std::string>(res.ret_val ));
223- ++t.realHoldersCount ;
224- }
225- }
226- }
227- }
187+ t.totalSupply = totalSupply;
228188}
229189
230190/* Call under data lock only */
@@ -269,6 +229,73 @@ void TokensMaster::updateTokenChaches(const csdb::Address& addr, const std::stri
269229 initiateHolder (tIt->second , tIt->first , regDude);
270230 }
271231 }
232+
233+ // Balance update
234+ auto refreshBalance = [&](const csdb::Address& addrFrom, const csdb::Address& addrTo = csdb::Address{}, const std::string& amount = " " ) {
235+ auto getCurrBalance = [&](const csdb::Address& addrOwner) -> std::string {
236+ bool present = false ;
237+ auto byteCodeObjects = api_->getSmartByteCode (addr, present);
238+ if (!present || byteCodeObjects.empty ()) return " 0" ;
239+
240+ general::Address addrToken{ addr.public_key ().begin (), addr.public_key ().end () };
241+
242+ auto dpAddrPK = tokens_[addr].owner .public_key ();
243+ general::Address dpAddr{ dpAddrPK.begin (), dpAddrPK.end () };
244+
245+ // param: owner
246+ std::vector<general::Variant> param (1 );
247+ std::string addrOwnerStr = addrOwner.to_api_addr ();
248+ param[0 ].__set_v_string (EncodeBase58 ({ addrOwnerStr.begin (), addrOwnerStr.end () }));
249+ //
250+ std::string retBalance{ " 0" };
251+ executeAndCall<std::string>(api_, dpAddr, addrToken, byteCodeObjects, newState, " balanceOf" , param,
252+ [&retBalance](const std::string& balance) { retBalance = balance; });
253+
254+ if (!std::all_of (retBalance.begin (), retBalance.end (), [](char ch) { return (isdigit (ch) || ch == ' .' ); })) {
255+ retBalance = " 0" ;
256+ cserror () << " executor return text balance!" ;
257+ }
258+ return retBalance;
259+ };
260+
261+ auto & t = tokens_[addr];
262+ if (addrTo == csdb::Address{}) { // for deploy token
263+ t.holders [addrFrom].balance = getCurrBalance (addrFrom);
264+ ++t.realHoldersCount ;
265+ return ;
266+ }
267+
268+ // from
269+ auto & currFromBalance = t.holders [addrFrom].balance ;
270+ auto newFromBalance = [&] {
271+ if (isZeroAmount (currFromBalance))
272+ return getCurrBalance (addrFrom);
273+ else
274+ return std::to_string (stof (currFromBalance) - stof (amount));
275+ }();
276+ if (isZeroAmount (newFromBalance))
277+ --t.realHoldersCount ;
278+ currFromBalance = newFromBalance;
279+
280+ // to
281+ auto & currToBalance = t.holders [addrTo].balance ;
282+ auto newToBalance = [&] {
283+ if (isZeroAmount (currToBalance))
284+ return getCurrBalance (addrTo);
285+ else
286+ return std::to_string (stof (currToBalance) + stof (amount));
287+ }();
288+ if (isZeroAmount (currToBalance) && !isZeroAmount (newToBalance))
289+ ++t.realHoldersCount ;
290+ currToBalance = newToBalance;
291+ };
292+
293+ if (ps.method == " transfer" && ps.params .size () == 2 )
294+ refreshBalance (ps.initiator , tryExtractPublicKey (ps.params [0 ].v_string ), ps.params [1 ].v_string );
295+ else if (ps.method == " transferFrom" && ps.params .size () == 3 )
296+ refreshBalance (tryExtractPublicKey (ps.params [0 ].v_string ), tryExtractPublicKey (ps.params [1 ].v_string ), ps.params [2 ].v_string );
297+ else if (ps.method .empty ()) // deploy token
298+ refreshBalance (tokens_[addr].owner );
272299}
273300
274301void TokensMaster::checkNewDeploy (const csdb::Address& sc, const csdb::Address& deployer, const api::SmartContractInvocation& sci) {
@@ -303,40 +330,24 @@ void TokensMaster::checkNewState(const csdb::Address& sc, const csdb::Address& i
303330 updateTokenChaches (sc, newState, ps);
304331}
305332
306- void TokensMaster::loadTokenInfo (const std::vector<csdb::Address>& vtokenAddr, const std::function<void (const TokensMap&, const HoldersMap&)> func, bool needLoad ) {
333+ void TokensMaster::loadTokenInfo (const std::vector<csdb::Address>& vtokenAddr, const std::function<void (const TokensMap&, const HoldersMap&)> func) {
307334 std::lock_guard<decltype (dataMut_)> l (dataMut_);
308- if (!needLoad ) {
335+ if (vtokenAddr. empty () ) {
309336 func (tokens_, holders_);
310337 return ;
311338 }
312- auto freeChache = [&tokens_ = tokens_](const csdb::Address& addr, bool checkBalance = true ) {
313- tokens_[addr].name = " not loaded" ;
314- tokens_[addr].symbol = " not loaded" ;
315- tokens_[addr].totalSupply = " not loaded" ;
316- if (checkBalance) {
317- for (auto & h : tokens_[addr].holders )
318- h.second .balance = " not loaded" ;
319- }
320- };
321-
322- if (!vtokenAddr.empty ()) {
323- TokensMap loadedToken;
324- for (const auto & addr : vtokenAddr) {
325- if (tokens_.find (addr) == tokens_.end ())
326- continue ;
327- refreshTokenState (addr, cs::SmartContracts::get_contract_state (api_->get_s_blockchain (), addr));
328- loadedToken[addr] = tokens_[addr];
329- }
330- func (loadedToken, holders_);
331- for (const auto & itLoaded : loadedToken)
332- freeChache (itLoaded.first );
333- }
334- else {
335- for (const auto & tk : tokens_) // need for sort
336- refreshTokenState (tk.first , cs::SmartContracts::get_contract_state (api_->get_s_blockchain (), tk.first ), false );
337- func (tokens_, holders_);
338- for (const auto & tk : tokens_)
339- freeChache (tk.first , false );
339+ TokensMap loadedToken;
340+ for (const auto & addr : vtokenAddr) {
341+ if (tokens_.find (addr) == tokens_.end ())
342+ continue ;
343+ refreshTokenState (addr, cs::SmartContracts::get_contract_state (api_->get_s_blockchain (), addr));
344+ loadedToken[addr] = tokens_[addr];
345+ }
346+ func (loadedToken, holders_);
347+ for (const auto & itLoaded : loadedToken) {
348+ tokens_[itLoaded.first ].name = " not loaded" ;
349+ tokens_[itLoaded.first ].symbol = " not loaded" ;
350+ tokens_[itLoaded.first ].totalSupply = " not loaded" ;
340351 }
341352}
342353
@@ -380,7 +391,7 @@ void TokensMaster::checkNewDeploy(const csdb::Address&, const csdb::Address&, co
380391}
381392void TokensMaster::checkNewState (const csdb::Address&, const csdb::Address&, const api::SmartContractInvocation&, const std::string&) {
382393}
383- void TokensMaster::loadTokenInfo (const std::vector<csdb::Address>&, const std::function<void (const TokensMap&, const HoldersMap&)>, bool ) {
394+ void TokensMaster::loadTokenInfo (const std::vector<csdb::Address>&, const std::function<void (const TokensMap&, const HoldersMap&)>) {
384395}
385396bool TokensMaster::isTransfer (const std::string&, const std::vector<general::Variant>&) {
386397 return false ;
0 commit comments