fixed ipfs image decoding
This commit is contained in:
parent
ea83f8eb0a
commit
956f788218
|
|
@ -9,6 +9,7 @@ use Contractless\Api\Http\JsonResponse;
|
||||||
use Contractless\Api\Http\Request;
|
use Contractless\Api\Http\Request;
|
||||||
use Contractless\Api\Http\Router;
|
use Contractless\Api\Http\Router;
|
||||||
use Contractless\Api\Nft\NftMediaService;
|
use Contractless\Api\Nft\NftMediaService;
|
||||||
|
use Contractless\Api\Rpc\RpcReplyDecoder;
|
||||||
|
|
||||||
final class NftMediaRoutes
|
final class NftMediaRoutes
|
||||||
{
|
{
|
||||||
|
|
@ -52,12 +53,10 @@ final class NftMediaRoutes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$series = Request::queryInt('series', 0, 0, 4_294_967_295);
|
$series = Request::queryInt('series', 0, 0, 4_294_967_295);
|
||||||
$reply = $application->client->nftDetails($name, $series);
|
$details = RpcReplyDecoder::nftDetails(
|
||||||
\Contractless\Api\Rpc\RpcReplyDecoder::notNodeError($reply);
|
$application->client->nftDetails($name, $series),
|
||||||
if (strlen($reply) < 173) {
|
);
|
||||||
throw new \RuntimeException('The node returned invalid NFT details.');
|
$cid = $details['item_ipfs'];
|
||||||
}
|
|
||||||
$cid = trim(substr($reply, 73, 100), "\0 ");
|
|
||||||
return [$name, $series, $cid];
|
return [$name, $series, $cid];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,10 +222,8 @@ final class RemainingRoutes
|
||||||
$name = self::assetName(Request::queryString('name', 15));
|
$name = self::assetName(Request::queryString('name', 15));
|
||||||
$series = Request::queryInt('series', 0, 0, 4_294_967_295);
|
$series = Request::queryInt('series', 0, 0, 4_294_967_295);
|
||||||
JsonResponse::success(
|
JsonResponse::success(
|
||||||
['name' => $name, 'series' => $series]
|
RpcReplyDecoder::nftDetails(
|
||||||
+ RpcReplyDecoder::jsonTextOrRaw(
|
|
||||||
$application->client->nftDetails($name, $series),
|
$application->client->nftDetails($name, $series),
|
||||||
'NFT details',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,112 @@ final class RpcReplyDecoder
|
||||||
return $nfts;
|
return $nfts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{
|
||||||
|
* nft_name: string,
|
||||||
|
* series: int,
|
||||||
|
* asset_name: string,
|
||||||
|
* genesis_txid: string,
|
||||||
|
* creator: string,
|
||||||
|
* item_ipfs: string,
|
||||||
|
* metadata_uri: string,
|
||||||
|
* current_holder: string|null,
|
||||||
|
* history_count: int,
|
||||||
|
* history: list<array<string, mixed>>
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public static function nftDetails(string $reply): array
|
||||||
|
{
|
||||||
|
self::notNodeError($reply);
|
||||||
|
$fixedBytes = 15 + 4 + 32 + 22 + 100 + 22 + 4;
|
||||||
|
$historyBytes = 109;
|
||||||
|
if (strlen($reply) < $fixedBytes) {
|
||||||
|
throw new RuntimeException('The node returned truncated NFT details.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = 0;
|
||||||
|
$name = rtrim(substr($reply, $offset, 15), "\0 ");
|
||||||
|
$offset += 15;
|
||||||
|
$series = self::u32($reply, $offset);
|
||||||
|
$genesisTxid = bin2hex(substr($reply, $offset, 32));
|
||||||
|
$offset += 32;
|
||||||
|
$creator = self::walletAddress(substr($reply, $offset, 22));
|
||||||
|
$offset += 22;
|
||||||
|
$cid = rtrim(substr($reply, $offset, 100), "\0 ");
|
||||||
|
$offset += 100;
|
||||||
|
$holderBytes = substr($reply, $offset, 22);
|
||||||
|
$holder = $holderBytes === str_repeat("\0", 22)
|
||||||
|
? null
|
||||||
|
: self::walletAddress($holderBytes);
|
||||||
|
$offset += 22;
|
||||||
|
$historyCount = self::u32($reply, $offset);
|
||||||
|
|
||||||
|
$expected = $fixedBytes + ($historyCount * $historyBytes);
|
||||||
|
if (strlen($reply) !== $expected) {
|
||||||
|
throw new RuntimeException('The node returned invalid NFT history data.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = [
|
||||||
|
1 => 'Create',
|
||||||
|
2 => 'Transfer',
|
||||||
|
3 => 'Swap',
|
||||||
|
4 => 'Loan Locked',
|
||||||
|
5 => 'Loan Payment',
|
||||||
|
6 => 'Collateral Claimed',
|
||||||
|
7 => 'Loan Issued',
|
||||||
|
8 => 'Burned',
|
||||||
|
];
|
||||||
|
$history = [];
|
||||||
|
for ($index = 0; $index < $historyCount; $index++) {
|
||||||
|
$txid = bin2hex(substr($reply, $offset, 32));
|
||||||
|
$offset += 32;
|
||||||
|
$block = self::u32($reply, $offset);
|
||||||
|
$transactionType = ord($reply[$offset++]);
|
||||||
|
$actionType = ord($reply[$offset++]);
|
||||||
|
$fromBytes = substr($reply, $offset, 22);
|
||||||
|
$offset += 22;
|
||||||
|
$toBytes = substr($reply, $offset, 22);
|
||||||
|
$offset += 22;
|
||||||
|
$receivedAsset = rtrim(substr($reply, $offset, 15), "\0 ");
|
||||||
|
$offset += 15;
|
||||||
|
$receivedSeries = self::u32($reply, $offset);
|
||||||
|
$receivedValue = self::u64($reply, $offset);
|
||||||
|
$history[] = [
|
||||||
|
'txid' => $txid,
|
||||||
|
'block' => $block,
|
||||||
|
'transaction_type' => $transactionType,
|
||||||
|
'action' => $actions[$actionType] ?? 'Unknown',
|
||||||
|
'from' => $fromBytes === str_repeat("\0", 22)
|
||||||
|
? null
|
||||||
|
: self::walletAddress($fromBytes),
|
||||||
|
'to' => $toBytes === str_repeat("\0", 22)
|
||||||
|
? null
|
||||||
|
: self::walletAddress($toBytes),
|
||||||
|
'received_asset' => $receivedAsset,
|
||||||
|
'received_series' => $receivedSeries,
|
||||||
|
'received_value_atomic' => $receivedValue,
|
||||||
|
'received_value' => self::decimal($receivedValue),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$metadataUri = $series > 0 && !str_ends_with($cid, '.json')
|
||||||
|
? 'ipfs://' . rtrim($cid, '/') . '/metadata/' . $series . '.json'
|
||||||
|
: 'ipfs://' . $cid;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'nft_name' => $name,
|
||||||
|
'series' => $series,
|
||||||
|
'asset_name' => $series > 0 ? $name . '_' . $series : $name,
|
||||||
|
'genesis_txid' => $genesisTxid,
|
||||||
|
'creator' => $creator,
|
||||||
|
'item_ipfs' => $cid,
|
||||||
|
'metadata_uri' => $metadataUri,
|
||||||
|
'current_holder' => $holder,
|
||||||
|
'history_count' => $historyCount,
|
||||||
|
'history' => $history,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{
|
* @return array{
|
||||||
* total_bytes: int,
|
* total_bytes: int,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue