Created
May 15, 2024 03:05
-
-
Save romanzaycev/5ffa380efabf152a272231a6bc6e0919 to your computer and use it in GitHub Desktop.
[PHP][TON] On-chain and semi-chain jetton metadata
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types=1); | |
use Brick\Math\BigInteger; | |
use Http\Client\Common\HttpMethodsClient; | |
use Http\Client\Common\HttpMethodsClientInterface; | |
use Http\Discovery\Psr17FactoryDiscovery; | |
use Http\Discovery\Psr18ClientDiscovery; | |
use Olifanton\Interop\Address; | |
use Olifanton\Interop\Boc\BitString; | |
use Olifanton\Interop\Boc\Cell; | |
use Olifanton\Interop\Boc\SnakeString; | |
use Olifanton\Ton\Contracts\Jetton\JettonMetadata; | |
use Olifanton\Ton\Contracts\Jetton\JettonMinter; | |
use Olifanton\Ton\JettonOffchainMetadataFetcher; | |
use Olifanton\Ton\Transport; | |
use Olifanton\Ton\Transports\Toncenter\ClientOptions; | |
use Olifanton\Ton\Transports\Toncenter\ToncenterHttpV2Client; | |
use Olifanton\Ton\Transports\Toncenter\ToncenterTransport; | |
require __DIR__ . "/vendor/autoload.php"; | |
define("TONCENTER_API_KEY_MAINNET", ""); | |
// | |
$httpClient = new HttpMethodsClient( | |
Psr18ClientDiscovery::find(), | |
Psr17FactoryDiscovery::findRequestFactory(), | |
Psr17FactoryDiscovery::findStreamFactory(), | |
); | |
$toncenter = new ToncenterHttpV2Client( | |
$httpClient, | |
new ClientOptions( | |
"https://toncenter.com/api/v2", | |
TONCENTER_API_KEY_MAINNET, | |
), | |
); | |
$transport = new ToncenterTransport($toncenter); | |
$metadataFetcher = new JettonOffchainMetadataFetcher($transport, $httpClient); | |
class UniversalMetadataFetcher | |
{ | |
public function __construct( | |
private readonly Transport $transport, | |
private readonly JettonOffchainMetadataFetcher $fetcher, | |
private readonly HttpMethodsClientInterface $httpClient, | |
) {} | |
public function getMetadata(Address $jettonMinterAddress): ?JettonMetadata | |
{ | |
try { | |
return $this->fetcher->getMetadataFromData( | |
JettonMinter::fromAddress($this->transport, $jettonMinterAddress)->getJettonData($this->transport), | |
); | |
} catch (\Throwable $e) {} | |
// Try parse offchain metadata | |
$stack = $this | |
->transport | |
->runGetMethod( | |
$jettonMinterAddress, | |
"get_jetton_data", | |
); | |
$stack->next(); | |
$stack->next(); | |
$stack->next(); | |
$jettonContentCell = $stack->currentCell(); | |
$jccSlice = $jettonContentCell->beginParse(); | |
if ($jccSlice->loadUint(8)->isEqualTo(0x00)) { | |
$metadataDict = $jccSlice->loadDict( | |
256, | |
new \Olifanton\Interop\Boc\DictSerializers( | |
keySerializer: fn (string $key, int $keySize): array => BitString::empty() | |
->writeUint(BigInteger::fromBytes(hash("sha256", $key, true), false), $keySize) | |
->toBitsA(), | |
valueDeserializer: fn (Cell $v): string => SnakeString::parse($v)->getData(), | |
) | |
); | |
$onchainKeys = [ | |
"name", | |
"description", | |
"image", | |
"symbol", | |
"image_data", | |
"decimals", | |
"uri", | |
"amount_style", | |
"render_type", | |
]; | |
$onchainMetadata = []; | |
foreach ($onchainKeys as $key) { | |
try { | |
$data = $metadataDict->get($key); | |
$onchainMetadata[$key] = $data; | |
} catch (\Throwable $e) {} | |
} | |
if ($onchainMetadata["uri"]) { | |
$metadataJsonStr = $this->httpClient->get($onchainMetadata["uri"])->getBody()->getContents(); | |
$metadataJson = json_decode($metadataJsonStr, true, flags: JSON_THROW_ON_ERROR); | |
$onchainMetadata = array_merge($onchainMetadata, $metadataJson); | |
} | |
return JettonMetadata::fromJson($onchainMetadata); | |
} | |
return null; | |
} | |
} | |
// Test | |
$cases = [ | |
"USDt" => new Address("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"), | |
"jUSDT" => new Address("EQBynBO23ywHy_CgarY9NK9FTz0yDsG82PtcbSTQgGoXwiuA"), | |
"Glint" => new Address("EQCBdxpECfEPH2wUxi1a6QiOkSf-5qDjUWqLCUuKtD-GLINT"), | |
"Notcoin" => new Address("EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT"), | |
"durev" => new Address("EQB02DJ0cdUD4iQDRbBv4aYG3htePHBRK1tGeRtCnatescK0"), | |
]; | |
$f = new UniversalMetadataFetcher($transport, $metadataFetcher, $httpClient); | |
foreach ($cases as $token => $jettonAddr) { | |
echo $token, ":", PHP_EOL; | |
var_dump($f->getMetadata($jettonAddr)); | |
echo "===", PHP_EOL, PHP_EOL; | |
} | |
/** | |
* USDt: | |
* onchain-metadata.php:127: | |
* class Olifanton\Ton\Contracts\Jetton\JettonMetadata#297 (6) { | |
* public readonly string $name => | |
* string(10) "Tether USD" | |
* public readonly string $description => | |
* string(27) "Tether Token for Tether USD" | |
* public readonly string $symbol => | |
* string(6) "USD₮" | |
* public readonly ?string $imageData => | |
* NULL | |
* public readonly int $decimals => | |
* int(6) | |
* public readonly ?string $image => | |
* string(39) "https://tether.to/images/logoCircle.png" | |
* } | |
* === | |
* | |
* jUSDT: | |
* onchain-metadata.php:127: | |
* class Olifanton\Ton\Contracts\Jetton\JettonMetadata#773 (6) { | |
* public readonly string $name => | |
* string(13) "Bridged jUSDT" | |
* public readonly string $description => | |
* string(127) "Tether USD transferred from Ethereum via bridge.ton.org. Token address in Ethereum: 0xdac17f958d2ee523a2206206994597c13d831ec7." | |
* public readonly string $symbol => | |
* string(5) "jUSDT" | |
* public readonly ?string $imageData => | |
* NULL | |
* public readonly int $decimals => | |
* int(6) | |
* public readonly ?string $image => | |
* string(77) "https://bridge.ton.org/token/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png" | |
* } | |
* === | |
* | |
* Glint: | |
* onchain-metadata.php:127: | |
* class Olifanton\Ton\Contracts\Jetton\JettonMetadata#1198 (6) { | |
* public readonly string $name => | |
* string(10) "Glint Coin" | |
* public readonly string $description => | |
* string(150) "Glint Coin is a utility token from TON Diamonds, an NFT Marketplace on TON Blockchain. Visit ton.diamonds to learn more about all utilities of $GLINT." | |
* public readonly string $symbol => | |
* string(5) "GLINT" | |
* public readonly ?string $imageData => | |
* NULL | |
* public readonly int $decimals => | |
* int(9) | |
* public readonly ?string $image => | |
* string(39) "https://nft.ton.diamonds/glint_meta.png" | |
* } | |
* === | |
* | |
* Notcoin: | |
* onchain-metadata.php:127: | |
* class Olifanton\Ton\Contracts\Jetton\JettonMetadata#384 (6) { | |
* public readonly string $name => | |
* string(7) "Notcoin" | |
* public readonly string $description => | |
* string(16) "Probably nothing" | |
* public readonly string $symbol => | |
* string(3) "NOT" | |
* public readonly ?string $imageData => | |
* NULL | |
* public readonly int $decimals => | |
* int(9) | |
* public readonly ?string $image => | |
* string(50) "https://cdn.joincommunity.xyz/clicker/not_logo.png" | |
* } | |
* === | |
* | |
* durev: | |
* onchain-metadata.php:127: | |
* class Olifanton\Ton\Contracts\Jetton\JettonMetadata#571 (6) { | |
* public readonly string $name => | |
* string(11) "povel durev" | |
* public readonly string $description => | |
* string(36) "mek bellions TONs of memes durev.xyz" | |
* public readonly string $symbol => | |
* string(5) "durev" | |
* public readonly ?string $imageData => | |
* NULL | |
* public readonly int $decimals => | |
* int(9) | |
* public readonly ?string $image => | |
* string(34) "https://durev.xyz/images/256-b.png" | |
* } | |
* === | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment