From a12b93a34cf0f3b3189541fccdaddc0d509a9731 Mon Sep 17 00:00:00 2001 From: Lorgansar Date: Fri, 26 Apr 2024 16:59:35 +0500 Subject: [PATCH 1/7] Rework TON main module, relying on an improved API --- CONTRIBUTORS.md | 1 + Modules/Common/TONLikeMainModule.php | 257 +++++++++++++++------------ Modules/TONMainModule.php | 14 +- 3 files changed, 152 insertions(+), 120 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f041e1f1..dac199be 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,5 +10,6 @@ - BRC-20 module * [Oleg Makaussov](https://github.com/Lorgansar) - Cardano Tokens modules + - Toncoin modules * [Kirill Kuzminykh](https://github.com/Oskal174) - Rootstock modules diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index 6100dfe9..8de1b1f2 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -1,7 +1,7 @@ workchain)) throw new DeveloperError("`workchain` is not set"); + if (is_null($this->workchain)) throw new DeveloperError('`workchain` is not set'); + } + + public function inquire_latest_block() + { + $result = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height', + params: [ + 'args' => [ + 'latest', + false + ] + ], + timeout: $this->timeout); + + return (int)$result['seqno']; + } + + public function ensure_block($block_id, $break_on_first = false) + { + $block = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height', + params: [ + 'args' => [ + $block_id, + false + ] + ], + timeout: $this->timeout); + + $this->block_hash = strtolower($block['filehash'] . $block['roothash']); + $this->block_time = date('Y-m-d H:i:s', (int)$block['timestamp']); } final public function pre_process_block($block_id) @@ -58,135 +91,125 @@ final public function pre_process_block($block_id) return; } - $block_times = []; - $events = []; - $sort_key = 0; + $block = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height', + params: [ + 'args' => [ + $block_id, + true + ] + ], + timeout: $this->timeout); - $rq_blocks = []; - $rq_blocks_data = []; + $events = []; + $inter_tx = 0; - foreach ($this->shards as $shard => $shard_data) + foreach ($block['transactions'] as $transaction) { - $this_root_hash = strtoupper($shard_data['roothash']); - $this_block_hash = strtoupper($shard_data['filehash']); - - $rq_blocks[] = requester_multi_prepare( - $this->select_node(), - endpoint: "blockLite?workchain={$this->workchain}&shard={$shard}&seqno={$block_id}&roothash={$this_root_hash}&filehash={$this_block_hash}", - timeout: $this->timeout + if (explode(',', substr($transaction['block'], 1), 2)[0] != $this->workchain) // ignore any other chain beside specified + continue; + + [$sub, $add] = $this->generate_event_pair( + $transaction['hash'], + $transaction['account'], + 'the-void', + $transaction['fee'], + $transaction['lt'], + $inter_tx, + 0, + 'fee', + $transaction['block'] ); - } - - $rq_blocks_multi = requester_multi( - $rq_blocks, - limit: envm($this->module, 'REQUESTER_THREADS'), - timeout: $this->timeout, - valid_codes: [200] - ); - - foreach ($rq_blocks_multi as $v) - $rq_blocks_data[] = requester_multi_process($v, flags: [RequesterOption::RecheckUTF8]); + array_push($events, $sub, $add); + + $is_from_nowhere = $transaction['imsg_src'] == 'NOWHERE'; + $is_to_nowhere = $transaction['imsg_dst'] == 'NOWHERE'; + + [$sub, $add] = $this->generate_event_pair( + $transaction['hash'], + ($is_from_nowhere) ? 'the-void' : $transaction['imsg_src'], + ($is_to_nowhere) ? 'the-void' : $transaction['imsg_dst'], + $transaction['imsg_grams'], + $transaction['lt'], + $inter_tx, + 1, + ($is_from_nowhere || $is_to_nowhere) ? 'ext' : null, + $transaction['block'] + ); + array_push($events, $sub, $add); - foreach ($rq_blocks_data as $block) - { - $block_times[] = (int)$block['header']['time']; - - foreach ($block['transactions'] as $transaction) - { - $transaction['hash'] = strtolower($transaction['hash']); - - if (!isset($transaction['messageIn'])) - { - if (isset($transaction['fee'])) - throw new ModuleError("There's fee, but no messageIn"); - - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => $transaction['addr'], - 'sort_key' => $sort_key++, - 'effect' => '-0', - 'extra' => 'n', - ]; - - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => 'the-void', - 'sort_key' => $sort_key++, - 'effect' => '0', - 'extra' => 'n', - ]; - } - else - { - if (count($transaction['messageIn']) > 1) - throw new ModuleError('count(messageIn) > 1'); - - $this_message_in = $transaction['messageIn']['0']; - - // Transaction fee - - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => $this_message_in['source'] ?? $transaction['address'], - 'sort_key' => $sort_key++, - 'effect' => '-' . $transaction['fee'], - 'extra' => 'f', - ]; - - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => 'the-void', - 'sort_key' => $sort_key++, - 'effect' => $transaction['fee'], - 'extra' => 'f', - ]; - - // The transfer itself - - if (isset($this_message_in['value'])) - { - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => $this_message_in['source'], - 'sort_key' => $sort_key++, - 'effect' => '-' . $this_message_in['value'], - 'extra' => null, - ]; - - $events[] = [ - 'transaction' => $transaction['hash'], - 'address' => $this_message_in['destination'], - 'sort_key' => $sort_key++, - 'effect' => $this_message_in['value'], - 'extra' => null, - ]; - } - } - } + $inter_tx++; } - //////////////// - // Processing // - //////////////// - - $max_block_time = date('Y-m-d H:i:s', max($block_times)); + array_multisort( + array_column($events, 'lt_sort'), SORT_ASC, // first, sort by lt - chronological order is most important + array_column($events, 'inter_tx'), SORT_ASC, // then, if any tx happened in diff shards, BUT at the same lt - by arbitrary synthetic "transaction-id" + array_column($events, 'intra_tx'), SORT_ASC, // lastly, ensure within transaction order: (-fee, +fee, -value, +value) + $events + ); + $sort_key = 0; foreach ($events as &$event) { $event['block'] = $block_id; - $event['time'] = $max_block_time; - } + $event['time'] = $this->block_time; + $event['sort_key'] = $sort_key++; - $this->block_time = $max_block_time; + unset($event['lt_sort']); + unset($event['inter_tx']); + unset($event['intra_tx']); + } $this->set_return_events($events); + } // Getting balances from the node public function api_get_balance($address) { - return (string)requester_single($this->select_node(), - endpoint: "account?account={$address}", - timeout: $this->timeout)['balance']; + $response = requester_single($this->select_node(), + endpoint: 'get_account_info', + params: [ + $address, true + ], + timeout: $this->timeout); + if (!array_key_exists('balance', $response)) + { + return "0"; + } + + if (!array_key_exists('grams', $response['balance'])) + { + return "0"; + } + + return (string)$response['balance']['grams']; + } + + + final public function generate_event_pair($tx, $src, $dst, $amt, $lt_sort, $inter_tx, $intra_tx, $extra, $extra_indexed) + { + $sub = [ + 'transaction' => $tx, + 'address' => $src, + 'effect' => '-' . $amt, + 'lt_sort' => $lt_sort, + 'inter_tx' => $inter_tx, + 'intra_tx' => 2 * ($intra_tx), + 'extra' => $extra, + 'extra_indexed' => $extra_indexed + ]; + $add = [ + 'transaction' => $tx, + 'address' => $dst, + 'effect' => $amt, + 'lt_sort' => $lt_sort, + 'inter_tx' => $inter_tx, + 'intra_tx' => 2 * ($intra_tx) + 1, + 'extra' => $extra, + 'extra_indexed' => $extra_indexed + ]; + return [$sub, $add]; } } diff --git a/Modules/TONMainModule.php b/Modules/TONMainModule.php index 317f5e62..3318c2e4 100644 --- a/Modules/TONMainModule.php +++ b/Modules/TONMainModule.php @@ -1,7 +1,7 @@ module = 'ton-main'; $this->is_main = true; $this->currency = 'ton'; - $this->currency_details = ['name' => 'TON', 'symbol' => '💎', 'decimals' => 9, 'description' => null]; + $this->currency_details = ['name' => 'Toncoin', 'symbol' => 'TON', 'decimals' => 9, 'description' => null]; $this->first_block_date = '2019-11-15'; - $this->first_block_id = 0; + $this->first_block_id = 1; // TONLikeMainModule $this->workchain = '0'; // BaseChain + + // Tests + $this->tests = [ + // first block, must be empty + ['block' => 1, 'result' => 'a:2:{s:6:"events";a:0:{}s:10:"currencies";N;}'], + // early low activity block with int and ext messages + ['block' => 2000, 'result' => 'a:2:{s:6:"events";a:8:{i:0;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:8:"-5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:1:"0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"b9d488d7f68444d11de600b149325fc83f0d93117403b92ddbe4de41f6632fff";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:8:"the-void";s:6:"effect";s:1:"0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:17:"-1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"b9d488d7f68444d11de600b149325fc83f0d93117403b92ddbe4de41f6632fff";s:6:"effect";s:16:"1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:7;}}s:10:"currencies";N;}'], + ]; } } From 72ddc240903f78e23b0639dbff77cf5771adee42 Mon Sep 17 00:00:00 2001 From: Lorgansar Date: Thu, 19 Sep 2024 18:12:57 +0500 Subject: [PATCH 2/7] add TON tokens support --- Modules/Common/TONLikeJettonModule.php | 245 -------------------- Modules/Common/TONLikeMainModule.php | 81 +------ Modules/Common/TONLikeNFJettonModule.php | 281 ----------------------- Modules/Common/TONLikeTokensModule.php | 257 +++++++++++++++++++++ Modules/Common/TONTraits.php | 115 ++++------ Modules/TONJettonModule.php | 12 +- Modules/TONMainModule.php | 27 ++- Modules/TONNFJettonModule.php | 24 -- Modules/TONNFTModule.php | 30 +++ 9 files changed, 376 insertions(+), 696 deletions(-) delete mode 100644 Modules/Common/TONLikeJettonModule.php delete mode 100644 Modules/Common/TONLikeNFJettonModule.php create mode 100644 Modules/Common/TONLikeTokensModule.php delete mode 100644 Modules/TONNFJettonModule.php create mode 100644 Modules/TONNFTModule.php diff --git a/Modules/Common/TONLikeJettonModule.php b/Modules/Common/TONLikeJettonModule.php deleted file mode 100644 index d1c67543..00000000 --- a/Modules/Common/TONLikeJettonModule.php +++ /dev/null @@ -1,245 +0,0 @@ -version = 1; - } - - final public function post_post_initialize() - { - // - } - - final public function pre_process_block($block_id) - { - if ($block_id === 0) // Block #0 is there, but the node doesn't return data for it - { - $this->block_time = date('Y-m-d H:i:s', 0); - $this->set_return_events([]); - $this->set_return_currencies([]); - return; - } - - $events = []; - $currencies_to_process = []; - $sort_key = 0; - - $rq_blocks = []; - $rq_blocks_data = []; - $block_times = []; - - foreach ($this->shards as $shard => $shard_data) - { - $this_root_hash = strtoupper($shard_data['roothash']); - $this_block_hash = strtoupper($shard_data['filehash']); - - $rq_blocks[] = requester_multi_prepare( - $this->select_node(), - endpoint: "blockLite?workchain={$this->workchain}&shard={$shard}&seqno={$block_id}&roothash={$this_root_hash}&filehash={$this_block_hash}", - timeout: $this->timeout - ); - } - - $rq_blocks_multi = requester_multi( - $rq_blocks, - limit: envm($this->module, 'REQUESTER_THREADS'), - timeout: $this->timeout, - valid_codes: [200] - ); - - foreach ($rq_blocks_multi as $v) - $rq_blocks_data[] = requester_multi_process($v, flags: [RequesterOption::RecheckUTF8]); - - foreach ($rq_blocks_data as $block) - { - $block_times[] = (int)$block['header']['time']; - - foreach ($block['transactions'] as $transaction) - { - $transaction['hash'] = strtolower($transaction['hash']); - - if (isset($transaction['messageIn'])) - { - $messageIn = $transaction['messageIn'][0]; // by default in TON there is only 1 message IN - if (isset($messageIn['transfer'])) - { - if ($transaction['messageIn'][0]['transfer']['transfer_type'] === 'transfer_notification' - || $transaction['messageIn'][0]['transfer']['transfer_type'] === 'internal_transfer') - { - $events[] = [ - 'transaction' => $transaction['hash'], - 'currency' => ($transaction['messageIn'][0]['transfer']['token'] !== '') ? $transaction['messageIn'][0]['transfer']['token'] : 'undefined-asset', - 'address' => ($transaction['messageIn'][0]['transfer']['from'] !== '') ? $transaction['messageIn'][0]['transfer']['from'] : 'the-abyss', - 'sort_key' => $sort_key++, - 'effect' => '-' . $transaction['messageIn'][0]['transfer']['amount'], - 'failed' => $transaction['messageIn'][0]['transfer']['failed'], - ]; - - $events[] = [ - 'transaction' => $transaction['hash'], - 'currency' => ($transaction['messageIn'][0]['transfer']['token'] !== '') ? $transaction['messageIn'][0]['transfer']['token'] : 'undefined-asset', - 'address' => ($transaction['messageIn'][0]['destination'] !== '') ? $transaction['messageIn'][0]['destination'] : 'the-abyss', - 'sort_key' => $sort_key++, - 'effect' => $transaction['messageIn'][0]['transfer']['amount'], - 'failed' => $transaction['messageIn'][0]['transfer']['failed'], - ]; - - if ($transaction['messageIn'][0]['transfer']['token'] !== '') - $currencies_to_process[] = ($transaction['messageIn'][0]['transfer']['token'] !== '') ? $transaction['messageIn'][0]['transfer']['token'] : 'undefined-asset'; - } - } - } - } - } - - // Process currencies - - $currencies = []; - - $currencies_to_process = array_values(array_unique($currencies_to_process)); // Removing duplicates - $currencies_to_process = check_existing_currencies($currencies_to_process, $this->currency_format); // Removes already known currencies - - if ($currencies_to_process) - { - $multi_curl = []; - $currency_data = []; - - foreach ($currencies_to_process as $currency_id) - { - if ($currency_id === 'undefined-asset') // here we suppose that it will be only 1 undef_curr and no more - { - $currencies[] = [ - 'id' => 'undefined-asset', - 'name' => '', - 'symbol' => '', - 'decimals' => 0, - ]; - continue; - } - $multi_curl[] = requester_multi_prepare($this->select_node(), - endpoint: "/account?account={$currency_id}&unpack=true", - timeout: $this->timeout); - } - - $curl_results = requester_multi($multi_curl, - limit: envm($this->module, 'REQUESTER_THREADS'), - timeout: $this->timeout); - - foreach ($curl_results as $v) - $currency_data[] = requester_multi_process($v, ignore_errors: true); - - foreach ($currency_data as $account_data) - { - $metadata = []; - if (isset($account_data["contract_state"]["contract_data"]["jetton_content"]["metadata"])) - { - $metadata = $account_data["contract_state"]["contract_data"]["jetton_content"]["metadata"]; - } - // This removes invalid UTF-8 sequences - $currencies[] = [ - 'id' => $account_data['account'], - 'name' => isset($metadata["name"]) ? mb_convert_encoding($metadata["name"], 'UTF-8', 'UTF-8') : '', - 'symbol' => isset($metadata['symbol']) ? mb_convert_encoding($metadata["symbol"], 'UTF-8', 'UTF-8') : '', - 'decimals' => isset($metadata['decimals']) ? ($metadata["decimals"] > 32767 ? 0 : $metadata['decimals']) : 0, - ]; - } - } - - //////////////// - // Processing // - //////////////// - - $max_block_time = date('Y-m-d H:i:s', max($block_times)); - - foreach ($events as &$event) - { - $event['block'] = $block_id; - $event['time'] = $max_block_time; - } - - $this->block_time = $max_block_time; - - $this->set_return_events($events); - $this->set_return_currencies($currencies); - } - - // Getting balances from the node - function api_get_balance(string $address, array $currencies): array - { - if (!$currencies) - return []; - - $real_currencies = []; - $jetton_array = "["; - - // Input currencies should be in format like this: `ton-jetton/EQDpQ2E8wCsG6OVq_5B3VmCkdD8gRrj124vh-5rh3aKUfDST` - foreach ($currencies as $c) - { - $currency = explode('/', $c)[1]; - $real_currencies[] = $currency; - $jetton_array .= ($currency . ","); - } - - $jetton_array .= "]"; - - $return = []; - - $account_info = requester_single( - $this->select_node(), - endpoint: "account?account={$address}&jettons={$jetton_array}", - timeout: $this->timeout - )['jettons']; - - $account_currencies_info = array_column($account_info, 'balance', 'token'); - - foreach($real_currencies as $c) - { - if (isset($account_currencies_info[$c])) - $return[] = $account_currencies_info[$c]; - else - $return[] = null; - } - - return $return; - } -} diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index 8de1b1f2..85360c55 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -49,39 +49,6 @@ final public function post_post_initialize() if (is_null($this->workchain)) throw new DeveloperError('`workchain` is not set'); } - public function inquire_latest_block() - { - $result = requester_single( - $this->select_node(), - endpoint: 'get_blocks/by_master_height', - params: [ - 'args' => [ - 'latest', - false - ] - ], - timeout: $this->timeout); - - return (int)$result['seqno']; - } - - public function ensure_block($block_id, $break_on_first = false) - { - $block = requester_single( - $this->select_node(), - endpoint: 'get_blocks/by_master_height', - params: [ - 'args' => [ - $block_id, - false - ] - ], - timeout: $this->timeout); - - $this->block_hash = strtolower($block['filehash'] . $block['roothash']); - $this->block_time = date('Y-m-d H:i:s', (int)$block['timestamp']); - } - final public function pre_process_block($block_id) { if ($block_id === 0) // Block #0 is there, but the node doesn't return data for it @@ -103,7 +70,6 @@ final public function pre_process_block($block_id) timeout: $this->timeout); $events = []; - $inter_tx = 0; foreach ($block['transactions'] as $transaction) { @@ -116,15 +82,14 @@ final public function pre_process_block($block_id) 'the-void', $transaction['fee'], $transaction['lt'], - $inter_tx, 0, 'fee', $transaction['block'] ); array_push($events, $sub, $add); - $is_from_nowhere = $transaction['imsg_src'] == 'NOWHERE'; - $is_to_nowhere = $transaction['imsg_dst'] == 'NOWHERE'; + $is_from_nowhere = $transaction['imsg_src'] === 'NOWHERE'; + $is_to_nowhere = $transaction['imsg_dst'] === 'NOWHERE'; [$sub, $add] = $this->generate_event_pair( $transaction['hash'], @@ -132,19 +97,16 @@ final public function pre_process_block($block_id) ($is_to_nowhere) ? 'the-void' : $transaction['imsg_dst'], $transaction['imsg_grams'], $transaction['lt'], - $inter_tx, 1, ($is_from_nowhere || $is_to_nowhere) ? 'ext' : null, $transaction['block'] ); array_push($events, $sub, $add); - - $inter_tx++; } array_multisort( array_column($events, 'lt_sort'), SORT_ASC, // first, sort by lt - chronological order is most important - array_column($events, 'inter_tx'), SORT_ASC, // then, if any tx happened in diff shards, BUT at the same lt - by arbitrary synthetic "transaction-id" + array_column($events, 'transaction'), SORT_ASC, // then, if any tx happened in diff shards, BUT at the same lt - arbitrarily, by tx-hash array_column($events, 'intra_tx'), SORT_ASC, // lastly, ensure within transaction order: (-fee, +fee, -value, +value) $events ); @@ -157,7 +119,6 @@ final public function pre_process_block($block_id) $event['sort_key'] = $sort_key++; unset($event['lt_sort']); - unset($event['inter_tx']); unset($event['intra_tx']); } @@ -171,45 +132,17 @@ public function api_get_balance($address) $response = requester_single($this->select_node(), endpoint: 'get_account_info', params: [ - $address, true - ], + 'args' => [ + $address, false + ] + ], timeout: $this->timeout); if (!array_key_exists('balance', $response)) - { return "0"; - } if (!array_key_exists('grams', $response['balance'])) - { return "0"; - } return (string)$response['balance']['grams']; } - - - final public function generate_event_pair($tx, $src, $dst, $amt, $lt_sort, $inter_tx, $intra_tx, $extra, $extra_indexed) - { - $sub = [ - 'transaction' => $tx, - 'address' => $src, - 'effect' => '-' . $amt, - 'lt_sort' => $lt_sort, - 'inter_tx' => $inter_tx, - 'intra_tx' => 2 * ($intra_tx), - 'extra' => $extra, - 'extra_indexed' => $extra_indexed - ]; - $add = [ - 'transaction' => $tx, - 'address' => $dst, - 'effect' => $amt, - 'lt_sort' => $lt_sort, - 'inter_tx' => $inter_tx, - 'intra_tx' => 2 * ($intra_tx) + 1, - 'extra' => $extra, - 'extra_indexed' => $extra_indexed - ]; - return [$sub, $add]; - } } diff --git a/Modules/Common/TONLikeNFJettonModule.php b/Modules/Common/TONLikeNFJettonModule.php deleted file mode 100644 index 3aba5219..00000000 --- a/Modules/Common/TONLikeNFJettonModule.php +++ /dev/null @@ -1,281 +0,0 @@ -version = 1; - } - - final public function post_post_initialize() - { - // - } - - final public function pre_process_block($block_id) - { - if ($block_id === 0) // Block #0 is there, but the node doesn't return data for it - { - $this->block_time = date('Y-m-d H:i:s', 0); - $this->set_return_events([]); - $this->set_return_currencies([]); - return; - } - - $events = []; - $currencies_to_process = []; - $sort_key = 0; - - $rq_blocks = []; - $rq_blocks_data = []; - $block_times = []; - - foreach ($this->shards as $shard => $shard_data) - { - $this_root_hash = strtoupper($shard_data['roothash']); - $this_block_hash = strtoupper($shard_data['filehash']); - - $rq_blocks[] = requester_multi_prepare( - $this->select_node(), - endpoint: "blockLite?workchain={$this->workchain}&shard={$shard}&seqno={$block_id}&roothash={$this_root_hash}&filehash={$this_block_hash}", - timeout: $this->timeout - ); - } - - $rq_blocks_multi = requester_multi( - $rq_blocks, - limit: envm($this->module, 'REQUESTER_THREADS'), - timeout: $this->timeout, - valid_codes: [200] - ); - - foreach ($rq_blocks_multi as $v) - $rq_blocks_data[] = requester_multi_process($v, flags: [RequesterOption::RecheckUTF8]); - - foreach ($rq_blocks_data as $block) - { - $block_times[] = (int)$block['header']['time']; - - foreach ($block['transactions'] as $transaction) - { - $transaction['hash'] = strtolower($transaction['hash']); - - if (isset($transaction['messageIn'])) - { - $messageIn = $transaction['messageIn'][0]; // by default in TON there is only 1 message IN - - if (isset($messageIn['transfer'])) - { - if (in_array($transaction['messageIn'][0]['transfer']['transfer_type'], ["transfer", "deploy_nft"]) - && $transaction['messageIn'][0]['transfer']['type'] === 'nft') - { - $token_info = $this->api_get_nft_info($transaction['messageIn'][0]['transfer']['token']); - - $events[] = [ - 'transaction' => $transaction['hash'], - 'currency' => ($token_info['collection_address'] !== '') ? $token_info['collection_address'] : 'undefined-asset', - 'address' => ($transaction['messageIn'][0]['transfer']['from'] !== '') ? $transaction['messageIn'][0]['transfer']['from'] : 'the-abyss', - 'sort_key' => $sort_key++, - 'effect' => '-1', - 'extra' => $token_info['index'], - 'extra_indexed' => $transaction['messageIn'][0]['transfer']['token'], - 'failed' => $transaction['messageIn'][0]['transfer']['failed'], - ]; - - $events[] = [ - 'transaction' => $transaction['hash'], - 'currency' => ($token_info['collection_address'] !== '') ? $token_info['collection_address'] : 'undefined-asset', - 'address' => ($transaction['messageIn'][0]['transfer']['to'] !== '') ? $transaction['messageIn'][0]['transfer']['to'] : 'the-abyss', - 'sort_key' => $sort_key++, - 'effect' => '1', - 'extra' => $token_info['index'], - 'extra_indexed' => $transaction['messageIn'][0]['transfer']['token'], - 'failed' => $transaction['messageIn'][0]['transfer']['failed'], - ]; - - if ($token_info['collection_address'] !== '') - $currencies_to_process[] = $token_info['collection_address']; - } - } - } - } - } - - // Process currencies - - $currencies = []; - - $currencies_to_process = array_values(array_unique($currencies_to_process)); // Removing duplicates - $currencies_to_process = check_existing_currencies($currencies_to_process, $this->currency_format); // Removes already known currencies - - if ($currencies_to_process) - { - $multi_curl = []; - $currency_data = []; - - foreach ($currencies_to_process as $currency_id) - { - if ($currency_id === 'undefined-asset') // here we suppose that it will be only 1 undef_curr and no more - { - $currencies[] = [ - 'id' => 'undefined-asset', - 'name' => '', - 'symbol' => '', - ]; - continue; - } - $multi_curl[] = requester_multi_prepare($this->select_node(), - endpoint: "account?account={$currency_id}", - timeout: $this->timeout); - } - - $curl_results = requester_multi($multi_curl, - limit: envm($this->module, 'REQUESTER_THREADS'), - timeout: $this->timeout); - - foreach ($curl_results as $v) - $currency_data[] = requester_multi_process($v, ignore_errors: true); - - foreach ($currency_data as $account_data) - { - $metadata = []; - if (isset($account_data["contract_state"]["contract_data"]["collection_content"]["metadata"])) - { - $metadata = $account_data["contract_state"]["contract_data"]["collection_content"]["metadata"]; - } - $currencies[] = [ - 'id' => $account_data['account'], - 'name' => isset($metadata['name']) ? mb_convert_encoding($metadata['name'], 'UTF-8', 'UTF-8') : '', - 'symbol' => isset($metadata['symbol']) ? mb_convert_encoding($metadata['symbol'], 'UTF-8', 'UTF-8') : '', - ]; - } - } - - //////////////// - // Processing // - //////////////// - - $max_block_time = date('Y-m-d H:i:s', max($block_times)); - - foreach ($events as &$event) - { - $event['block'] = $block_id; - $event['time'] = $max_block_time; - } - - $this->block_time = $max_block_time; - - $this->set_return_events($events); - $this->set_return_currencies($currencies); - } - - // get collection address and index of nft - private function api_get_nft_info($nft) - { - try { - $nft_info = requester_single( - $this->select_node(), - endpoint: "account?account={$nft}", - timeout: $this->timeout, - flags: [RequesterOption::RecheckUTF8] - ); - } catch (RequesterException) - { - $nft_info = null; - } - - if (isset($nft_info['contract_state']['contract_data'])) - { - $contract_data = $nft_info['contract_state']['contract_data']; - return [ - 'collection_address' => isset($contract_data['collection_address']) ? $contract_data['collection_address'] : 'undefined-asset', - 'index' => isset($contract_data['index']) ? $contract_data['index'] : null , - ]; - } - else - return [ - 'collection_address' => 'undefined-asset', - 'index' => null, - ]; - } - - // Getting amount of NFTs from the node by collection - function api_get_balance(string $address, array $currencies): array - { - if (!$currencies) - return []; - - $real_currencies = []; - $collection_array = "["; - - // Input currencies should be in format like this: `ton-nft/EQDpQ2E8wCsG6OVq_5B3VmCkdD8gRrj124vh-5rh3aKUfDST` - foreach ($currencies as $c) - { - $currency = explode('/', $c)[1]; - $real_currencies[] = $currency; - $collection_array .= ($currency . ","); - } - - $collection_array .= "]"; - - $return = []; - - $account_info = requester_single( - $this->select_node(), - endpoint: "account?account={$address}&nfts_count={$collection_array}", - timeout: $this->timeout - )['nfts_count']; - - $account_currencies_info = array_column($account_info, 'balance', 'token'); - - foreach ($real_currencies as $c) - { - if (isset($account_currencies_info[$c])) - $return[] = $account_currencies_info[$c]; - else - $return[] = null; - } - - return $return; - } -} diff --git a/Modules/Common/TONLikeTokensModule.php b/Modules/Common/TONLikeTokensModule.php new file mode 100644 index 00000000..5fa16ee0 --- /dev/null +++ b/Modules/Common/TONLikeTokensModule.php @@ -0,0 +1,257 @@ +version = 1; + } + + final public function post_post_initialize() + { + if (is_null($this->workchain)) throw new DeveloperError('`workchain` is not set'); + if (is_null($this->currency_type)) throw new DeveloperError('`currency_type` is not set'); + } + + final public function pre_process_block($block_id) + { + if ($block_id === 0) // Block #0 is there, but the node doesn't return data for it + { + $this->block_time = date('Y-m-d H:i:s', 0); + $this->set_return_events([]); + $this->set_return_currencies([]); + return; + } + + $block = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height/tokens', + params: [ + 'args' => [ + $block_id, + true + ] + ], + timeout: $this->timeout); + + $events = []; + $currencies_to_process = []; + + foreach ($block['token_transfers'] as $transaction) + { + if (explode(',', substr($transaction['block'], 1), 2)[0] != $this->workchain) // ignore any other chain beside specified + continue; + + if ($transaction['token_type'] == 'Jetton' && $this->currency_type == CurrencyType::NFT) + continue; + + if ($transaction['token_type'] == 'NFT' && $this->currency_type == CurrencyType::FT) + continue; + + [$src, $dst] = $this->remap_participants($transaction); + + // ignore broken transfers and non-std tokens + if ($src == '' || $dst == '' || $transaction['token'] == "Unknown") + continue; + + [$sub, $add] = $this->generate_event_pair( + $transaction['in_transaction'], + $src, + $dst, + ($transaction['amount'] == "") ? '1' : $transaction['amount'], + $transaction['lt'], + 1, + null, + $transaction['block'] + ); + $sub['currency'] = $transaction['token']; + $add['currency'] = $transaction['token']; + + array_push($events, $sub, $add); + + $currencies_to_process[] = $transaction['token']; + } + + array_multisort( + array_column($events, 'lt_sort'), SORT_ASC, // first, sort by lt - chronological order is most important + array_column($events, 'transaction'), SORT_ASC, // then, if any tx happened in diff shards, BUT at the same lt - arbitrarily, by tx-hash + array_column($events, 'intra_tx'), SORT_ASC, // lastly, ensure within transaction order: (-fee, +fee, -value, +value) + $events + ); + + $sort_key = 0; + foreach ($events as &$event) + { + $event['block'] = $block_id; + $event['time'] = $this->block_time; + $event['sort_key'] = $sort_key++; + + unset($event['lt_sort']); + unset($event['intra_tx']); + unset($event['extra']); + } + + $this->set_return_events($events); + + // Process currencies + + $currencies = []; + + $currencies_to_process = array_values(array_unique($currencies_to_process)); // Removing duplicates + $currencies_to_process = check_existing_currencies($currencies_to_process, $this->currency_format); // Removes already known currencies + + foreach ($currencies_to_process as $currency_id) + { + $currency_data = requester_single( + $this->select_node(), + endpoint: 'get_token_info', + params: [ + 'args' => [$currency_id] + ], + timeout: $this->timeout); + + $next_currency = [ + 'id' => $currency_id, + 'name' => $currency_data['token_name_pretty'] ?? "", + 'symbol' => $currency_data['symbol'] ?? "", + 'decimals' => $currency_data['decimals'] ?? '0' + ]; + + if (array_key_exists('offchain_metadata', $currency_data)) + { + try { + $offchain_data = requester_single( + $currency_data['offchain_metadata'], + endpoint: '', + timeout: $this->timeout); + + $next_currency['name'] = $offchain_data['name'] ?? $next_currency['name']; + $next_currency['symbol'] = $offchain_data['symbol'] ?? $next_currency['symbol']; + $next_currency['decimals'] = $offchain_data['decimals'] ?? $next_currency['decimals']; + } catch (Exception $e) {} + } + + if ($next_currency['name'] == 'Unknown' || $next_currency['name'] == '') + continue; + + $currencies[] = $next_currency; + } + $this->set_return_currencies($currencies); + + } + + // Getting balances from the node + public function api_get_balance($address, $currencies) + { + if (!$currencies) + return []; + + $real_currencies_map = []; + $return = []; + $i = 0; + // Input currencies should be in format like this: + // `ton-jetton/Ef9VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVbxn` - ton-jetton/ + // `ton-nft/Ef9VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVbxn` - ton-nft/ + foreach ($currencies as $c) + { + $return[] = '0'; + $real_currencies_map[explode('/', $c)[1]] = $i; + $i++; + } + + $response = requester_single($this->select_node(), + endpoint: 'get_account_info', + params: [ + "args" => [ + $address, true + ] + ], + timeout: $this->timeout); + + if (!array_key_exists('wallets', $response)) + return $return; + + foreach ($response['wallets'] as $w) + { + if (!array_key_exists('master_contract', $w)) + continue; + + if (!array_key_exists('balance', $w)) + continue; + + if (!array_key_exists($w['master_contract'], $real_currencies_map)) + continue; + + $id = $real_currencies_map[$w['master_contract']]; + + if ($this->currency_type == CurrencyType::FT && array_key_exists('jetton_balance', $w['balance'])) + $return[$id] = bcadd($return[$id], $w['balance']['jetton_balance']); + + if ($this->currency_type == CurrencyType::NFT && array_key_exists('NFT_index', $w['balance'])) + $return[$id] = bcadd($return[$id], '1'); + } + + return $return; + } + + final public function remap_participants($transfer) + { + switch ($transfer['type']) + { + case 'InterWallet': + case 'TransferNotify': + case 'OwnershipAssigned': + case 'JustTransfer': + case 'Transfer': + case 'DeployNFT': + $src = ($transfer['from'] != '') ? $transfer['from'] : $transfer['source']; + $dst = ($transfer['to'] != '') ? $transfer['to'] : $transfer['destination']; + return [$src, $dst]; + + default: + break; + } + return ['', '']; + } +} \ No newline at end of file diff --git a/Modules/Common/TONTraits.php b/Modules/Common/TONTraits.php index ef1acfe7..6099ca7a 100644 --- a/Modules/Common/TONTraits.php +++ b/Modules/Common/TONTraits.php @@ -1,7 +1,7 @@ select_node(), endpoint: 'lastNum', timeout: $this->timeout); - - return (int)$result[($this->workchain)][(array_key_first($result[($this->workchain)]))]['seqno']; - // This may be not the best solution in case there are several shard with different heights + $result = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height', + params: [ + 'args' => [ + 'latest', + false + ] + ], + timeout: $this->timeout); + + return (int)$result['seqno']; } public function ensure_block($block_id, $break_on_first = false) { - if ($block_id === 0) // Block #0 is there, but the node doesn't return data for it - { - $this->block_hash = ""; - return; - } - - $multi_curl = []; - - foreach ($this->nodes as $node) - { - $multi_curl[] = requester_multi_prepare($node, endpoint: "getHashByHeight?workchain={$this->workchain}&seqno={$block_id}", timeout: $this->timeout); - - if ($break_on_first) - break; - } - - try - { - $curl_results = requester_multi($multi_curl, limit: count($this->nodes), timeout: $this->timeout); - } - catch (RequesterException $e) - { - throw new RequesterException("ensure_block(block_id: {$block_id}): no connection, previously: " . $e->getMessage()); - } - - $hashes = requester_multi_process($curl_results[0]); - ksort($hashes, SORT_STRING); - - $shard_list = $final_filehash = []; - - foreach ($hashes as $shard => $shard_hashes) - { - $shard_list[] = $shard; - $final_filehash[] = $shard_hashes['filehash']; - - $this->shards[$shard] = ['filehash' => $shard_hashes['filehash'], 'roothash' => $shard_hashes['roothash']]; - } - - $this->block_hash = strtolower(implode($final_filehash)); - - $this->block_extra = strtolower(implode('/', $shard_list)); - - if (count($curl_results) > 0) - { - foreach ($curl_results as $result) - { - $this_hashes = requester_multi_process($result); - ksort($this_hashes, SORT_STRING); - - $this_final_filehash = []; - - foreach ($this_hashes as $shard => $shard_hashes) - { - $this_final_filehash[] = $shard_hashes['filehash']; - } + $block = requester_single( + $this->select_node(), + endpoint: 'get_blocks/by_master_height', + params: [ + 'args' => [ + $block_id, + false + ] + ], + timeout: $this->timeout); + + $this->block_hash = strtolower($block['filehash'] . $block['roothash']); + $this->block_time = date('Y-m-d H:i:s', (int)$block['timestamp']); + } - if (strtolower(implode($this_final_filehash)) !== $this->block_hash) - { - throw new ConsensusException("ensure_block(block_id: {$block_id}): no consensus"); - } - } - } + public function generate_event_pair($tx, $src, $dst, $amt, $lt_sort, $intra_tx, $extra, $extra_indexed) + { + $sub = [ + 'transaction' => $tx, + 'address' => $src, + 'effect' => '-' . $amt, + 'lt_sort' => $lt_sort, + 'intra_tx' => 2 * ($intra_tx), + 'extra' => $extra, + 'extra_indexed' => $extra_indexed + ]; + $add = [ + 'transaction' => $tx, + 'address' => $dst, + 'effect' => $amt, + 'lt_sort' => $lt_sort, + 'intra_tx' => 2 * ($intra_tx) + 1, + 'extra' => $extra, + 'extra_indexed' => $extra_indexed + ]; + return [$sub, $add]; } + } diff --git a/Modules/TONJettonModule.php b/Modules/TONJettonModule.php index 99ed6bbd..b702a921 100644 --- a/Modules/TONJettonModule.php +++ b/Modules/TONJettonModule.php @@ -7,7 +7,7 @@ /* This module works with the TEP-74 standard, see * https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md */ -final class TONJettonModule extends TONLikeJettonModule implements Module +final class TONJettonModule extends TONLikeTokensModule implements Module { function initialize() { @@ -16,9 +16,15 @@ function initialize() $this->module = 'ton-jetton'; $this->is_main = false; $this->first_block_date = '2019-11-15'; - $this->first_block_id = 0; + $this->first_block_id = 1; - // TONLikeMainModule + // TONLikeTokensModule $this->workchain = '0'; // BaseChain + $this->currency_type = CurrencyType::FT; + + // Tests + $this->tests = [ + ['block' => 40470016, 'result' => 'a:2:{s:6:"events";a:6:{i:0;a:8:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:13:"-614900000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQAJZF4OyGerASxjdBnsEhJTpLGCC8okIr4ZzkBTTYbZbMhE";s:6:"effect";s:12:"614900000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt";s:6:"effect";s:14:"-8569200000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQDMj00WZdlpEHY1_IQEkfgwanwLs6RhLnu9lxYYj3qlxCQX";s:6:"effect";s:13:"8569200000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:14:"-5431500000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQASNZzIszZwju0GPyu7yCYOLuR2_vUYcU11G--PlkVLN69w";s:6:"effect";s:13:"5431500000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:5;}}s:10:"currencies";a:1:{i:0;a:4:{s:2:"id";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:4:"name";s:6:"NOT-AI";s:6:"symbol";s:5:"NOTAI";s:8:"decimals";s:1:"9";}}}'], + ]; } } diff --git a/Modules/TONMainModule.php b/Modules/TONMainModule.php index 3318c2e4..aede0ec1 100644 --- a/Modules/TONMainModule.php +++ b/Modules/TONMainModule.php @@ -22,12 +22,33 @@ function initialize() // TONLikeMainModule $this->workchain = '0'; // BaseChain + // Handles + $this->handles_implemented = true; + $this->handles_regex = '/(0|-1):[0-9a-fA-F]{64}|(EQ|UQ)[0-9a-zA-Z_\-]{46}/'; // wc:raw-hex or b64-bounceable (EQ..) or b64-non-bounceable (UQ..) + $this->api_get_handle = function($handle) + { + $response = requester_single($this->select_node(), + endpoint: 'account_serialize', + params: [ + 'args' => [ + $handle + ] + ], + timeout: $this->timeout); + + if (!array_key_exists('valid', $response) || !array_key_exists('base64-bounceable', $response)) + return null; + + if (!$response['valid']) + return null; + + return $response['base64-bounceable']; + }; + // Tests $this->tests = [ - // first block, must be empty - ['block' => 1, 'result' => 'a:2:{s:6:"events";a:0:{}s:10:"currencies";N;}'], // early low activity block with int and ext messages - ['block' => 2000, 'result' => 'a:2:{s:6:"events";a:8:{i:0;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:8:"-5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:1:"0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"b9d488d7f68444d11de600b149325fc83f0d93117403b92ddbe4de41f6632fff";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:8:"the-void";s:6:"effect";s:1:"0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"8852e69acbb5394ae9b934fb45d1ede200002f711fc890e76d30ff0c3cd8b2b1";s:6:"effect";s:17:"-1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:64:"b9d488d7f68444d11de600b149325fc83f0d93117403b92ddbe4de41f6632fff";s:6:"effect";s:16:"1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:7;}}s:10:"currencies";N;}'], + ['block' => 2000, 'result' => 'a:2:{s:6:"events";a:8:{i:0;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:8:"-5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:1:"0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:8:"the-void";s:6:"effect";s:1:"0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:17:"-1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:16:"1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:7;}}s:10:"currencies";N;}'], ]; } } diff --git a/Modules/TONNFJettonModule.php b/Modules/TONNFJettonModule.php deleted file mode 100644 index ac5c8503..00000000 --- a/Modules/TONNFJettonModule.php +++ /dev/null @@ -1,24 +0,0 @@ -blockchain = 'ton'; - $this->module = 'ton-nft'; - $this->is_main = false; - $this->first_block_date = '2019-11-15'; - $this->first_block_id = 0; - - // TONLikeMainModule - $this->workchain = '0'; // BaseChain - } -} diff --git a/Modules/TONNFTModule.php b/Modules/TONNFTModule.php new file mode 100644 index 00000000..13dcc550 --- /dev/null +++ b/Modules/TONNFTModule.php @@ -0,0 +1,30 @@ +blockchain = 'ton'; + $this->module = 'ton-nft'; + $this->is_main = false; + $this->first_block_date = '2019-11-15'; + $this->first_block_id = 1; + + // TONLikeTokensModule + $this->workchain = '0'; // BaseChain + $this->currency_type = CurrencyType::NFT; + + // Tests + $this->tests = [ + ['block' => 40470001, 'result' => 'a:2:{s:6:"events";a:10:{i:0;a:8:{s:11:"transaction";s:64:"21178bd97fc9185a6622988af7b9de86ad67cbef4fe2c5d2d7fe00e6cfb26547";s:7:"address";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"21178bd97fc9185a6622988af7b9de86ad67cbef4fe2c5d2d7fe00e6cfb26547";s:7:"address";s:48:"EQBpHoCRURumt61BbOYbgb5JO6Y1-zwdHDTCgop4Eqsez9DJ";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"3717ec3fbed8e720a213579e77086a6b6458a94916dfd798e17a11f9373bfd6b";s:7:"address";s:48:"EQCA14o1-VWhS2efqoh_9M1b_A9DtKTuoqfmkn83AbJzwnPi";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"3717ec3fbed8e720a213579e77086a6b6458a94916dfd798e17a11f9373bfd6b";s:7:"address";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"477f2a1336c195aedc4cc0443afecd10d97ed418869cdbfd17153a59a667223f";s:7:"address";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"477f2a1336c195aedc4cc0443afecd10d97ed418869cdbfd17153a59a667223f";s:7:"address";s:48:"EQAJ-QU4xFrQRr1JCtQS7zAgCOvVDl5tkBvgwbAGOGiRd9MO";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"873e6a69b8ddf3f1604159080d9ba6f8dcb2d9ed885943506335040450dac9c1";s:7:"address";s:48:"EQDNU5WByVGCoG8EGJMT5wFH2rikzxFdpBM4WVR_abr51JOL";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"873e6a69b8ddf3f1604159080d9ba6f8dcb2d9ed885943506335040450dac9c1";s:7:"address";s:48:"EQCcpi3jRZqpTfxmatIMZSKeB3lKFPTCrqiNoSlLroanRc_F";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:7;}i:8;a:8:{s:11:"transaction";s:64:"9712b2343d3e790cee80d886887a3c1c126013506863e6dc3361fb962e12a219";s:7:"address";s:48:"EQDYnoGIvZqeKSN2ExwPAKKXhLJxv3Y17J8wD_uGb3WREGqG";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,9000000000000000,45737433)";s:8:"currency";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:8;}i:9;a:8:{s:11:"transaction";s:64:"9712b2343d3e790cee80d886887a3c1c126013506863e6dc3361fb962e12a219";s:7:"address";s:48:"EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,9000000000000000,45737433)";s:8:"currency";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:9;}}s:10:"currencies";a:3:{i:0;a:4:{s:2:"id";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:4:"name";s:30:"Bump Spaceship Modules pack. 2";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}i:1;a:4:{s:2:"id";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:4:"name";s:18:"Telegram Usernames";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}i:2;a:4:{s:2:"id";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:4:"name";s:10:"BeeHarvest";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}}}'], + ]; + } +} From 99c15b316fdcdb0fc77873a58a8a08415854c03a Mon Sep 17 00:00:00 2001 From: Nikita Zhavoronkov Date: Tue, 24 Sep 2024 14:01:28 -0400 Subject: [PATCH 3/7] Minimize extra data --- Modules/Common/TONLikeMainModule.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index 85360c55..b2107d7b 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -83,7 +83,7 @@ final public function pre_process_block($block_id) $transaction['fee'], $transaction['lt'], 0, - 'fee', + 'f', $transaction['block'] ); array_push($events, $sub, $add); @@ -98,7 +98,7 @@ final public function pre_process_block($block_id) $transaction['imsg_grams'], $transaction['lt'], 1, - ($is_from_nowhere || $is_to_nowhere) ? 'ext' : null, + ($is_from_nowhere || $is_to_nowhere) ? 'e' : null, $transaction['block'] ); array_push($events, $sub, $add); From de128ff7fc76c3adaac37090f2a88cfa43771add Mon Sep 17 00:00:00 2001 From: Nikita Zhavoronkov Date: Tue, 24 Sep 2024 14:05:46 -0400 Subject: [PATCH 4/7] Remove `SearchableEntity` as we can't search by tuples --- Modules/Common/TONLikeMainModule.php | 1 - Modules/Common/TONLikeTokensModule.php | 1 - 2 files changed, 2 deletions(-) diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index b2107d7b..e5ae2239 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -22,7 +22,6 @@ abstract class TONLikeMainModule extends CoreModule public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra', 'extra_indexed']; public ?array $events_table_nullable_fields = ['extra', 'extra_indexed']; - public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Block; public ?ExtraDataModel $extra_data_model = ExtraDataModel::Default; diff --git a/Modules/Common/TONLikeTokensModule.php b/Modules/Common/TONLikeTokensModule.php index 5fa16ee0..733fe083 100644 --- a/Modules/Common/TONLikeTokensModule.php +++ b/Modules/Common/TONLikeTokensModule.php @@ -22,7 +22,6 @@ abstract class TONLikeTokensModule extends CoreModule public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra_indexed', 'currency']; public ?array $events_table_nullable_fields = ['extra_indexed']; - public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Block; public ?ExtraDataModel $extra_data_model = ExtraDataModel::None; From 895cce2ac9a1cbfed82c3701a896e0f531ad638c Mon Sep 17 00:00:00 2001 From: Nikita Zhavoronkov Date: Tue, 24 Sep 2024 16:08:05 -0400 Subject: [PATCH 5/7] Introduce `SearchableEntity::Other` type --- Engine/Enums.php | 3 ++- Modules/Common/TONLikeMainModule.php | 1 + Modules/Common/TONLikeTokensModule.php | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Engine/Enums.php b/Engine/Enums.php index 92cafb78..9175a8c9 100644 --- a/Engine/Enums.php +++ b/Engine/Enums.php @@ -119,7 +119,7 @@ enum PrivacyModel case Shielded; // The only allowed values are `-?` and `+?` } -// This is for modules where `extra_indexed` is specified: here we can chose which entity it directs to +// This is for modules where `extra_indexed` is specified: here we can choose which entity it directs to enum SearchableEntity: string { case Block = 'block'; @@ -127,4 +127,5 @@ enum SearchableEntity: string case Address = 'address'; case Handle = 'handle'; case Any = 'any'; + case Other = 'other'; // Something that can't be found directly (not really indexed) } diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index 3fb836a5..3ae7d909 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -22,6 +22,7 @@ abstract class TONLikeMainModule extends CoreModule public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra', 'extra_indexed']; public ?array $events_table_nullable_fields = ['extra', 'extra_indexed']; + public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Other; public ?ExtraDataModel $extra_data_model = ExtraDataModel::Default; diff --git a/Modules/Common/TONLikeTokensModule.php b/Modules/Common/TONLikeTokensModule.php index 733fe083..63946045 100644 --- a/Modules/Common/TONLikeTokensModule.php +++ b/Modules/Common/TONLikeTokensModule.php @@ -22,6 +22,7 @@ abstract class TONLikeTokensModule extends CoreModule public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra_indexed', 'currency']; public ?array $events_table_nullable_fields = ['extra_indexed']; + public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Other; public ?ExtraDataModel $extra_data_model = ExtraDataModel::None; From 3ab646658e711e834340382d0791365e9764c0e5 Mon Sep 17 00:00:00 2001 From: Lorgansar Date: Tue, 3 Dec 2024 16:18:18 +0500 Subject: [PATCH 6/7] adjust ton get-balance endpoint to filter currencies and reduce node lag --- Modules/Common/TONLikeTokensModule.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Common/TONLikeTokensModule.php b/Modules/Common/TONLikeTokensModule.php index 63946045..fff6684e 100644 --- a/Modules/Common/TONLikeTokensModule.php +++ b/Modules/Common/TONLikeTokensModule.php @@ -92,7 +92,7 @@ final public function pre_process_block($block_id) [$src, $dst] = $this->remap_participants($transaction); // ignore broken transfers and non-std tokens - if ($src == '' || $dst == '' || $transaction['token'] == "Unknown") + if ($src == '' || $dst == '' || $transaction['token'] == 'Unknown') continue; [$sub, $add] = $this->generate_event_pair( @@ -203,8 +203,8 @@ public function api_get_balance($address, $currencies) $response = requester_single($this->select_node(), endpoint: 'get_account_info', params: [ - "args" => [ - $address, true + 'args' => [ + $address, 'tokens', array_keys($real_currencies_map) ] ], timeout: $this->timeout); From d97f12099d50398a1485842c4ac450006e761b1b Mon Sep 17 00:00:00 2001 From: Lorgansar Date: Fri, 14 Feb 2025 20:02:19 +0500 Subject: [PATCH 7/7] Enable combining init&exec transactions --- Modules/Common/TONLikeMainModule.php | 13 +++++++++---- Modules/Common/TONLikeTokensModule.php | 12 +++++++----- Modules/TONJettonModule.php | 6 +++--- Modules/TONMainModule.php | 2 +- Modules/TONNFTModule.php | 4 ++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Modules/Common/TONLikeMainModule.php b/Modules/Common/TONLikeMainModule.php index 3ae7d909..d934bd6c 100644 --- a/Modules/Common/TONLikeMainModule.php +++ b/Modules/Common/TONLikeMainModule.php @@ -22,7 +22,7 @@ abstract class TONLikeMainModule extends CoreModule public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra', 'extra_indexed']; public ?array $events_table_nullable_fields = ['extra', 'extra_indexed']; - public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Other; + public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Transaction; public ?ExtraDataModel $extra_data_model = ExtraDataModel::Default; @@ -76,15 +76,20 @@ final public function pre_process_block($block_id) if (explode(',', substr($transaction['block'], 1), 2)[0] != $this->workchain) // ignore any other chain beside specified continue; + $issued_in = (array_key_exists('issued_in', $transaction)) ? [ + 'hash' => $transaction['issued_in']['hash'], + 'fee' => $transaction['issued_in']['fee'] + ] : false; + [$sub, $add] = $this->generate_event_pair( $transaction['hash'], $transaction['account'], 'the-void', - $transaction['fee'], + ($issued_in) ? bcadd($transaction['fee'], $issued_in['fee']) : $transaction['fee'], $transaction['lt'], 0, 'f', - $transaction['block'] + ($issued_in) ? $issued_in['hash'] : null, ); array_push($events, $sub, $add); @@ -99,7 +104,7 @@ final public function pre_process_block($block_id) $transaction['lt'], 1, ($is_from_nowhere || $is_to_nowhere) ? 'e' : null, - $transaction['block'] + ($issued_in) ? $issued_in['hash'] : null ); array_push($events, $sub, $add); } diff --git a/Modules/Common/TONLikeTokensModule.php b/Modules/Common/TONLikeTokensModule.php index fff6684e..f1006b13 100644 --- a/Modules/Common/TONLikeTokensModule.php +++ b/Modules/Common/TONLikeTokensModule.php @@ -20,9 +20,8 @@ abstract class TONLikeTokensModule extends CoreModule public ?array $special_addresses = ['the-void']; public ?PrivacyModel $privacy_model = PrivacyModel::Transparent; - public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'extra_indexed', 'currency']; - public ?array $events_table_nullable_fields = ['extra_indexed']; - public ?SearchableEntity $extra_indexed_hint_entity = SearchableEntity::Other; + public ?array $events_table_fields = ['block', 'transaction', 'sort_key', 'time', 'address', 'effect', 'currency']; + public ?array $events_table_nullable_fields = []; public ?ExtraDataModel $extra_data_model = ExtraDataModel::None; @@ -103,11 +102,14 @@ final public function pre_process_block($block_id) $transaction['lt'], 1, null, - $transaction['block'] + null ); $sub['currency'] = $transaction['token']; $add['currency'] = $transaction['token']; + unset($sub['extra_indexed']); + unset($add['extra_indexed']); + array_push($events, $sub, $add); $currencies_to_process[] = $transaction['token']; @@ -182,7 +184,7 @@ final public function pre_process_block($block_id) } // Getting balances from the node - public function api_get_balance($address, $currencies) + public function api_get_balance(string $address, array $currencies): array { if (!$currencies) return []; diff --git a/Modules/TONJettonModule.php b/Modules/TONJettonModule.php index b702a921..2468b880 100644 --- a/Modules/TONJettonModule.php +++ b/Modules/TONJettonModule.php @@ -1,13 +1,13 @@ tests = [ - ['block' => 40470016, 'result' => 'a:2:{s:6:"events";a:6:{i:0;a:8:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:13:"-614900000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQAJZF4OyGerASxjdBnsEhJTpLGCC8okIr4ZzkBTTYbZbMhE";s:6:"effect";s:12:"614900000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt";s:6:"effect";s:14:"-8569200000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQDMj00WZdlpEHY1_IQEkfgwanwLs6RhLnu9lxYYj3qlxCQX";s:6:"effect";s:13:"8569200000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:14:"-5431500000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQASNZzIszZwju0GPyu7yCYOLuR2_vUYcU11G--PlkVLN69w";s:6:"effect";s:13:"5431500000000";s:13:"extra_indexed";s:29:"(0,a800000000000000,45734519)";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:06";s:8:"sort_key";i:5;}}s:10:"currencies";a:1:{i:0;a:4:{s:2:"id";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:4:"name";s:6:"NOT-AI";s:6:"symbol";s:5:"NOTAI";s:8:"decimals";s:1:"9";}}}'], + ['block' => 40470016, 'result' => 'a:2:{s:6:"events";a:6:{i:0;a:7:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:13:"-614900000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:0;}i:1;a:7:{s:11:"transaction";s:64:"27c9ae28bc1cbf57cd78caad716f566beef274d361ea8ab0d4973e68010fbaa4";s:7:"address";s:48:"EQAJZF4OyGerASxjdBnsEhJTpLGCC8okIr4ZzkBTTYbZbMhE";s:6:"effect";s:12:"614900000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:1;}i:2;a:7:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt";s:6:"effect";s:14:"-8569200000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:2;}i:3;a:7:{s:11:"transaction";s:64:"2eb5cdd0f9d4b600ca3d9d610e6bb9830e7c130431277a93f7f5672b9a24e73b";s:7:"address";s:48:"EQDMj00WZdlpEHY1_IQEkfgwanwLs6RhLnu9lxYYj3qlxCQX";s:6:"effect";s:13:"8569200000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:3;}i:4;a:7:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQDCTl1v-TPqf-X26w3JVqYokkAYsMz6BQK5Hkd7NeYWYjF8";s:6:"effect";s:14:"-5431500000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:4;}i:5;a:7:{s:11:"transaction";s:64:"815884a27116be0bc704bf64d4669d89e803012bbad1ef4b5be57d3472239697";s:7:"address";s:48:"EQASNZzIszZwju0GPyu7yCYOLuR2_vUYcU11G--PlkVLN69w";s:6:"effect";s:13:"5431500000000";s:8:"currency";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:5:"block";i:40470016;s:4:"time";s:19:"2024-09-18 10:51:10";s:8:"sort_key";i:5;}}s:10:"currencies";a:1:{i:0;a:4:{s:2:"id";s:48:"EQCV5dXNrWVU1z7VidEKvXL5iB_PXs2zm9LLe9bPgSklde0z";s:4:"name";s:6:"NOT-AI";s:6:"symbol";s:5:"NOTAI";s:8:"decimals";s:1:"9";}}}'], ]; } } diff --git a/Modules/TONMainModule.php b/Modules/TONMainModule.php index c00e276e..665e082e 100644 --- a/Modules/TONMainModule.php +++ b/Modules/TONMainModule.php @@ -48,7 +48,7 @@ function initialize() // Tests $this->tests = [ // early low activity block with int and ext messages - ['block' => 2000, 'result' => 'a:2:{s:6:"events";a:8:{i:0;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:8:"-5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:1:"0";s:5:"extra";s:3:"ext";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:2:"-0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:8:"the-void";s:6:"effect";s:1:"0";s:5:"extra";s:3:"fee";s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:17:"-1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:16:"1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:25:"(0,a000000000000000,2013)";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:7;}}s:10:"currencies";N;}'], + ['block' => 2000, 'result' => 'a:2:{s:6:"events";a:8:{i:0;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:8:"-5469072";s:5:"extra";s:1:"f";s:13:"extra_indexed";N;s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:1:"f";s:13:"extra_indexed";N;s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:8:"the-void";s:6:"effect";s:2:"-0";s:5:"extra";s:1:"e";s:13:"extra_indexed";N;s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:1:"0";s:5:"extra";s:1:"e";s:13:"extra_indexed";N;s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:8:"-5469072";s:5:"extra";s:1:"f";s:13:"extra_indexed";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:8:"the-void";s:6:"effect";s:7:"5469072";s:5:"extra";s:1:"f";s:13:"extra_indexed";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQCIUuaay7U5Sum5NPtF0e3iAAAvcR_IkOdtMP8MPNiyscnY";s:6:"effect";s:17:"-1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"c50629714cdad802b5e4f4372c293207b4de5801e8d0bfa7ea173bf0c04ba518";s:7:"address";s:48:"EQC51IjX9oRE0R3mALFJMl_IPw2TEXQDuS3b5N5B9mMv_15k";s:6:"effect";s:16:"1000000000000000";s:5:"extra";N;s:13:"extra_indexed";s:64:"b907dff4091671be391946fcd05de044283aa17e3fac9d92c87e85c96a5dacf7";s:5:"block";i:2000;s:4:"time";s:19:"2019-11-15 14:32:06";s:8:"sort_key";i:7;}}s:10:"currencies";N;}'], ]; } } diff --git a/Modules/TONNFTModule.php b/Modules/TONNFTModule.php index 13dcc550..2c418f0e 100644 --- a/Modules/TONNFTModule.php +++ b/Modules/TONNFTModule.php @@ -7,7 +7,7 @@ /* This module works with the TEP-74 standard, see * https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md */ -final class TONNFTModule extends TONLikeTokensModule implements Module +final class TONNFTModule extends TONLikeTokensModule implements Module, MultipleBalanceSpecial { function initialize() { @@ -24,7 +24,7 @@ function initialize() // Tests $this->tests = [ - ['block' => 40470001, 'result' => 'a:2:{s:6:"events";a:10:{i:0;a:8:{s:11:"transaction";s:64:"21178bd97fc9185a6622988af7b9de86ad67cbef4fe2c5d2d7fe00e6cfb26547";s:7:"address";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:0;}i:1;a:8:{s:11:"transaction";s:64:"21178bd97fc9185a6622988af7b9de86ad67cbef4fe2c5d2d7fe00e6cfb26547";s:7:"address";s:48:"EQBpHoCRURumt61BbOYbgb5JO6Y1-zwdHDTCgop4Eqsez9DJ";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:1;}i:2;a:8:{s:11:"transaction";s:64:"3717ec3fbed8e720a213579e77086a6b6458a94916dfd798e17a11f9373bfd6b";s:7:"address";s:48:"EQCA14o1-VWhS2efqoh_9M1b_A9DtKTuoqfmkn83AbJzwnPi";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:2;}i:3;a:8:{s:11:"transaction";s:64:"3717ec3fbed8e720a213579e77086a6b6458a94916dfd798e17a11f9373bfd6b";s:7:"address";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,7000000000000000,45754673)";s:8:"currency";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:3;}i:4;a:8:{s:11:"transaction";s:64:"477f2a1336c195aedc4cc0443afecd10d97ed418869cdbfd17153a59a667223f";s:7:"address";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:4;}i:5;a:8:{s:11:"transaction";s:64:"477f2a1336c195aedc4cc0443afecd10d97ed418869cdbfd17153a59a667223f";s:7:"address";s:48:"EQAJ-QU4xFrQRr1JCtQS7zAgCOvVDl5tkBvgwbAGOGiRd9MO";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQCbrTGaRq4PlAbSuse1HWDdRTrOcBqwLIq4k1spxXza4IOj";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:5;}i:6;a:8:{s:11:"transaction";s:64:"873e6a69b8ddf3f1604159080d9ba6f8dcb2d9ed885943506335040450dac9c1";s:7:"address";s:48:"EQDNU5WByVGCoG8EGJMT5wFH2rikzxFdpBM4WVR_abr51JOL";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:6;}i:7;a:8:{s:11:"transaction";s:64:"873e6a69b8ddf3f1604159080d9ba6f8dcb2d9ed885943506335040450dac9c1";s:7:"address";s:48:"EQCcpi3jRZqpTfxmatIMZSKeB3lKFPTCrqiNoSlLroanRc_F";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,1000000000000000,45755983)";s:8:"currency";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:7;}i:8;a:8:{s:11:"transaction";s:64:"9712b2343d3e790cee80d886887a3c1c126013506863e6dc3361fb962e12a219";s:7:"address";s:48:"EQDYnoGIvZqeKSN2ExwPAKKXhLJxv3Y17J8wD_uGb3WREGqG";s:6:"effect";s:2:"-1";s:13:"extra_indexed";s:29:"(0,9000000000000000,45737433)";s:8:"currency";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:8;}i:9;a:8:{s:11:"transaction";s:64:"9712b2343d3e790cee80d886887a3c1c126013506863e6dc3361fb962e12a219";s:7:"address";s:48:"EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";s:6:"effect";s:1:"1";s:13:"extra_indexed";s:29:"(0,9000000000000000,45737433)";s:8:"currency";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:5:"block";i:40470001;s:4:"time";s:19:"2024-09-18 10:50:08";s:8:"sort_key";i:9;}}s:10:"currencies";a:3:{i:0;a:4:{s:2:"id";s:48:"EQABEJDNwHqBnCc5TwHBRWY6Ynnmj_-dREOQDe8ybRKRfUVx";s:4:"name";s:30:"Bump Spaceship Modules pack. 2";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}i:1;a:4:{s:2:"id";s:48:"EQBte36QWZQuZE1INOdvKahaGjDIC3oM99YuYcAcJhvS_4LZ";s:4:"name";s:18:"Telegram Usernames";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}i:2;a:4:{s:2:"id";s:48:"EQCIQtrQTjYE0K5BxbNHurlTTKVFaxR0VXbViumXPF5IZwWH";s:4:"name";s:10:"BeeHarvest";s:6:"symbol";s:0:"";s:8:"decimals";s:1:"0";}}}'], + ['block' => 40470019, 'result' => 'a:2:{s:6:"events";a:10:{i:0;a:7:{s:11:"transaction";s:64:"27b86bd31997a933857649f84a9d1becc268644d3aaf8e2cb006625e395298e9";s:7:"address";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:6:"effect";s:2:"-1";s:8:"currency";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:0;}i:1;a:7:{s:11:"transaction";s:64:"27b86bd31997a933857649f84a9d1becc268644d3aaf8e2cb006625e395298e9";s:7:"address";s:48:"EQDqaeryhqu_kKxL0SQ8pNNYkrzeqx11zIgdDLPtd79S6jIR";s:6:"effect";s:1:"1";s:8:"currency";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:1;}i:2;a:7:{s:11:"transaction";s:64:"ba80008c916ab46fafd6b5e98f8dd0391a8b43994eb80850e8c08519f589082f";s:7:"address";s:48:"EQCwF7-OQiHBxKePiBFOAWwzHDTFHkJR9likOqTYFQc08OmS";s:6:"effect";s:2:"-1";s:8:"currency";s:48:"EQCVNxC9hPaC6b5nZz-GVy_psUN59Pocj2lXI44jUa0Q6rd8";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:2;}i:3;a:7:{s:11:"transaction";s:64:"ba80008c916ab46fafd6b5e98f8dd0391a8b43994eb80850e8c08519f589082f";s:7:"address";s:48:"EQDX5lXoYcWNwVd1TU4sQ-VsBSOB_NZeg-St9yrRWHQA4rWk";s:6:"effect";s:1:"1";s:8:"currency";s:48:"EQCVNxC9hPaC6b5nZz-GVy_psUN59Pocj2lXI44jUa0Q6rd8";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:3;}i:4;a:7:{s:11:"transaction";s:64:"c6529e2a71c76fa1ae1a5e0af0f0cd06d2f612deebc84987b6dc55227496d677";s:7:"address";s:48:"EQBrnSNI6soNcKlWjXl52APLwWnSrPdw0KIS9B99_xqo2lUf";s:6:"effect";s:2:"-1";s:8:"currency";s:48:"EQD6vxgaarq7nP6tW1sJHMQSzOTWV_PsPcOvck6coW_n3OnX";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:4;}i:5;a:7:{s:11:"transaction";s:64:"c6529e2a71c76fa1ae1a5e0af0f0cd06d2f612deebc84987b6dc55227496d677";s:7:"address";s:48:"EQDG3Pq7UHHzVEOTlj-lEHvOmdK8fDVKD6SyznWL8oqBpNvi";s:6:"effect";s:1:"1";s:8:"currency";s:48:"EQD6vxgaarq7nP6tW1sJHMQSzOTWV_PsPcOvck6coW_n3OnX";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:5;}i:6;a:7:{s:11:"transaction";s:64:"cfd87ca51cc5661dd66ecbfc1a9248230f0da4ab993feeaeb2e1acaf6ae8e4f1";s:7:"address";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:6:"effect";s:2:"-1";s:8:"currency";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:6;}i:7;a:7:{s:11:"transaction";s:64:"cfd87ca51cc5661dd66ecbfc1a9248230f0da4ab993feeaeb2e1acaf6ae8e4f1";s:7:"address";s:48:"EQCaafehYAv8Fy7po2dQoVt9JfepP4A5s9AY0_YKhbTt1fnL";s:6:"effect";s:1:"1";s:8:"currency";s:48:"EQDMp5nZQsqZOKWk8Q3SXmDEOmO7-_D6DP_jHHeSRJe32Y2j";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:7;}i:8;a:7:{s:11:"transaction";s:64:"702f252dee825cb03e82db8581a80341c17b596a4b284e19d60b35b8f1804911";s:7:"address";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:6:"effect";s:2:"-1";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:8;}i:9;a:7:{s:11:"transaction";s:64:"702f252dee825cb03e82db8581a80341c17b596a4b284e19d60b35b8f1804911";s:7:"address";s:48:"EQApQ5NY2iROFhV8hwB3u4se4c6oAmW20G60XP4rw5hiiEJl";s:6:"effect";s:1:"1";s:8:"currency";s:48:"EQAiZeV2VfsPksPAlcGGwOHUGAKnFs27w3GDpV9T45PMIFkH";s:5:"block";i:40470019;s:4:"time";s:19:"2024-09-18 10:51:22";s:8:"sort_key";i:9;}}s:10:"currencies";a:0:{}}'], ]; } }