diff --git a/src/BlockchainApi/BchdProtoGatewayApi.php b/src/BlockchainApi/BchdProtoGatewayApi.php index ee9cffa..120f103 100644 --- a/src/BlockchainApi/BchdProtoGatewayApi.php +++ b/src/BlockchainApi/BchdProtoGatewayApi.php @@ -111,7 +111,9 @@ public function getAddressDetails(string $address): ?BchAddress { return $bchAddress; foreach ($jsonRes->outputs as $output) { - $bchAddress->balanceSat += (int)$output->value; + $curSats = (int)$output->value; + if ($curSats > CashP::DUST_LIMIT) + $bchAddress->balanceSat += $curSats; } $bchAddress->balance = CashP::fromSatoshis($bchAddress->balanceSat); $bchAddress->transactions = $this->getAddressTransactions($address); @@ -135,7 +137,11 @@ public function getSlpAddressDetails(string $address, string $tokenID): ?SlpToke $this->logError("Error on receiving SLP address details", $jsonRes->error); return null; } - else if (!isset($jsonRes->token_metadata) || empty($jsonRes->token_metadata)) { + if (empty($jsonRes->outputs)) { + // on an address with 0 transactions token_meta on GetAddressUnspentOutputs is empty. we call GetTokenMetadata explicitly + $jsonRes->token_metadata = $this->getTokenMetadataRaw($tokenID); + } + if (!isset($jsonRes->token_metadata) || empty($jsonRes->token_metadata)) { $this->logError("Missing token metadata on SLP address details", $jsonRes); return null; } @@ -215,6 +221,25 @@ protected function getTransactionDetails(string $transactionID): ?\stdClass { return $jsonRes; } + protected function getTokenMetadataRaw(string $tokenID): array { + $tokenIDBase64 = static::ensureBase64Encoding($tokenID, false); + $url = $this->blockchainApiUrl . 'GetTokenMetadata'; + $data = array( + 'token_ids' => array($tokenIDBase64), + ); + $response = $this->httpAgent->post($url, $data); + if ($response === false) + return array(); + $jsonRes = json_decode($response); + if ($jsonRes === null) + return array(); + else if (isset($jsonRes->error) && $jsonRes->error === true) + return array(); + else if (empty($jsonRes->token_metadata)) + return array(); + return $jsonRes->token_metadata; // array with 1 element + } + protected function getAddressTransactions(string $address, $confirmedOnly = false): array { $transactions = array(); $url = $this->blockchainApiUrl . 'GetAddressTransactions'; diff --git a/src/CashP.php b/src/CashP.php index 6ed369d..e2d5dc0 100644 --- a/src/CashP.php +++ b/src/CashP.php @@ -12,6 +12,7 @@ */ class CashP { const BADGER_LIB_URL = "https://badgerwallet.cash/button.js"; + const DUST_LIMIT = 546; /** @var CashP */ //private static $instance = null; @@ -206,7 +207,7 @@ public function isValidSlpAddress(string $slpAddress): bool { } /** - * Gets the return BCH address (belonging to the sender senders address) defined + * Gets the return BCH address (belonging to the sender) defined * as the last address in transaction outputs. * @param Transaction $tx * @return string @@ -222,7 +223,7 @@ public function getReturnAddress(Transaction $tx): string { } /** - * Gets the return SLP address (belonging to the sender senders address) defined + * Gets the return SLP address (belonging to the sender) defined * as the last address in transaction outputs. * @param Transaction $tx * @return string diff --git a/tests/BchdBackendTest.php b/tests/BchdBackendTest.php index a920c7f..6cf2dc3 100644 --- a/tests/BchdBackendTest.php +++ b/tests/BchdBackendTest.php @@ -93,6 +93,17 @@ public function testGetSlpTransaction(): void { $this->assertEquals('simpleledger:qzapwgc088xj9hf8pcsrzsey8j7svcqysyp9ygxmq8', $returnAddress, 'wrong SLP return address'); } + public function testGetTokenMetadata(): void { + $cashp = $this->getCashpForTesting(); + + // on an address with 0 transactions token_meta on GetAddressUnspentOutputs is empty. call GetTokenMetadata explicitly + $slpAddress = 'simpleledger:qpfdgdftjj43f9fhzm2k4ysrcuwlae2l3vd4pvmhy7'; + $tokenID = 'c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479'; + $address = $cashp->getBlockchain()->getSlpAddressDetails($slpAddress, $tokenID); + $this->assertEquals('c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479', $address->id, 'invalid token ID returned from API'); + $this->assertEmpty($address->transactions, 'SLP ddress already has transactions. GetTokenMeta function not called.'); + } + protected function getCashpForTesting(): CashP { $opts = new CashpOptions(); $opts->blockchainApiImplementation = 'BchdProtoGatewayApi';