モザイクの作成
上級
モザイク は、通貨、コレクターズアイテム、アクセス権などをSymbolブロックチェーン上の資産を表します。
他のプラットフォームのトークンとは異なり、Symbolのモザイクはプロトコルレベルで直接サポートされているため、使用するために追加のコーディングは必要ありません。
単純な通貨から制限付きトークンまで、さまざまなユースケースをサポートするためにプロパティを構成できます。
このチュートリアルでは、モザイクを作成し、その初期供給量をミント(鋳造)する方法を説明します。
前提条件
開始する前に、以下を確認してください。
さらに、トランザクションがどのようにアナウンスされ承認されるかを理解するために、転送トランザクション のチュートリアルを復習しておいてください。
完全なコード
このチュートリアルの完全なコード一覧を以下に示します。
詳細な手順ごとの説明は次のセクションで行います。
import json
import os
import time
import urllib.request
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.symbol.IdGenerator import generate_mosaic_id
NODE_URL = os . getenv ( 'NODE_URL' , 'https://reference.symboltest.net:3001' )
print ( f 'Using node { NODE_URL } ' )
# Helper function to announce a transaction
def announce_transaction ( payload , label ):
print ( f 'Announcing { label } to /transactions' )
request = urllib . request . Request (
f ' { NODE_URL } /transactions' ,
data = payload . encode (),
headers = { 'Content-Type' : 'application/json' },
method = 'PUT'
)
with urllib . request . urlopen ( request ) as announce_response :
print ( f ' Response: { announce_response . read () . decode () } ' )
# Helper function to wait for transaction confirmation
def wait_for_confirmation ( tx_hash , label ):
print ( f 'Waiting for { label } confirmation...' )
for attempt in range ( 60 ):
time . sleep ( 1 )
try :
url = f ' { NODE_URL } /transactionStatus/ { tx_hash } '
with urllib . request . urlopen ( url ) as confirm_response :
status = json . loads ( confirm_response . read () . decode ())
print ( f ' Transaction status: { status [ "group" ] } ' )
if status [ 'group' ] == 'confirmed' :
print ( f ' { label } confirmed in { attempt } seconds' )
return
if status [ 'group' ] == 'failed' :
raise RuntimeError (
f ' { label } failed: { status [ "code" ] } ' )
except urllib . error . HTTPError :
print ( ' Transaction status: unknown' )
raise TimeoutError ( f ' { label } not confirmed after 60 seconds' )
SIGNER_PRIVATE_KEY = os . getenv ( 'SIGNER_PRIVATE_KEY' ,
'0000000000000000000000000000000000000000000000000000000000000000' )
signer_key_pair = SymbolFacade . KeyPair (
PrivateKey ( SIGNER_PRIVATE_KEY ))
facade = SymbolFacade ( 'testnet' )
signer_address = facade . network . public_key_to_address (
signer_key_pair . public_key )
print ( f 'Signer address: { signer_address } ' )
try :
# Fetch recommended fees
fee_path = '/network/fees/transaction'
print ( f 'Fetching recommended fees from { fee_path } ' )
with urllib . request . urlopen ( f ' { NODE_URL }{ fee_path } ' ) as response :
response_json = json . loads ( response . read () . decode ())
median_multiplier = response_json [ 'medianFeeMultiplier' ]
minimum_multiplier = response_json [ 'minFeeMultiplier' ]
fee_multiplier = max ( median_multiplier , minimum_multiplier )
print ( f ' Fee multiplier: { fee_multiplier } ' )
# --- CREATING MOSAIC DEFINITION ---
print ( ' \n --- Creating mosaic definition ---' )
nonce = int ( time . time ()) % 0x100000000
print ( f 'Mosaic nonce: { nonce } ' )
# Build the mosaic definition transaction
definition_tx = facade . create_transaction_from_descriptor (
{
'type' : 'mosaic_definition_transaction_v1' ,
'duration' : 0 ,
'divisibility' : 2 ,
'nonce' : nonce ,
'flags' : 'transferable restrictable'
},
signer_key_pair . public_key ,
fee_multiplier ,
2 * 60 * 60 )
mosaic_id = generate_mosaic_id ( signer_address , nonce )
print ( f 'Mosaic ID: { mosaic_id } (0x { mosaic_id : 016X } )' )
# Sign and generate final payload
signature = facade . sign_transaction ( signer_key_pair , definition_tx )
json_payload = facade . transaction_factory . attach_signature (
definition_tx , signature )
print ( 'Built mosaic definition transaction:' )
print ( json . dumps ( definition_tx . to_json (), indent = 2 ))
# Announce and wait for confirmation
definition_hash = facade . hash_transaction ( definition_tx )
print ( f 'Transaction hash: { definition_hash } ' )
announce_transaction ( json_payload , 'mosaic definition' )
wait_for_confirmation ( definition_hash , 'mosaic definition' )
# --- INCREASING MOSAIC SUPPLY ---
print ( ' \n --- Increasing mosaic supply ---' )
supply_tx = facade . create_transaction_from_descriptor (
{
'type' : 'mosaic_supply_change_transaction_v1' ,
'mosaic_id' : mosaic_id ,
'action' : 'increase' ,
'delta' : 100_00
},
signer_key_pair . public_key ,
fee_multiplier ,
2 * 60 * 60 )
# Sign and generate final payload
signature = facade . sign_transaction ( signer_key_pair , supply_tx )
json_payload = facade . transaction_factory . attach_signature (
supply_tx , signature )
print (
'Built mosaic supply change transaction:' )
print ( json . dumps ( supply_tx . to_json (), indent = 2 ))
# Announce and wait for confirmation
supply_hash = facade . hash_transaction ( supply_tx )
print ( f 'Transaction hash: { supply_hash } ' )
announce_transaction ( json_payload , 'mosaic supply change' )
wait_for_confirmation ( supply_hash , 'mosaic supply change' )
# --- VERIFYING MOSAIC ---
print ( ' \n --- Verifying mosaic ---' )
mosaic_id_hex = f ' { mosaic_id : 016X } '
mosaic_path = f '/mosaics/ { mosaic_id_hex } '
print ( f 'Fetching mosaic information from { mosaic_path } ' )
with urllib . request . urlopen ( f ' { NODE_URL }{ mosaic_path } ' ) as response :
response_json = json . loads ( response . read () . decode ())
mosaic_info = response_json [ 'mosaic' ]
print ( 'Mosaic information:' )
print ( f ' Mosaic ID: { mosaic_info [ "id" ] } ' )
print ( f ' Supply: { mosaic_info [ "supply" ] } ' )
print ( f ' Flags: { mosaic_info [ "flags" ] } ' )
print ( f ' Divisibility: { mosaic_info [ "divisibility" ] } ' )
print ( f ' Duration: { mosaic_info [ "duration" ] } ' )
except Exception as e :
print ( e )
Download source
import { PrivateKey } from 'symbol-sdk' ;
import {
SymbolFacade ,
descriptors ,
generateMosaicId ,
models
} from 'symbol-sdk/symbol' ;
const NODE_URL = process . env . NODE_URL ||
'https://reference.symboltest.net:3001' ;
console . log ( 'Using node' , NODE_URL );
// Helper function to announce a transaction
async function announceTransaction ( payload , label ) {
console . log ( `Announcing ${ label } to /transactions` );
const response = await fetch ( ` ${ NODE_URL } /transactions` , {
method : 'PUT' ,
headers : { 'Content-Type' : 'application/json' },
body : payload
});
console . log ( ' Response:' , await response . text ());
}
// Helper function to wait for transaction confirmation
async function waitForConfirmation ( transactionHash , label ) {
console . log ( `Waiting for ${ label } confirmation...` );
for ( let attempt = 0 ; 60 > attempt ; attempt ++ ) {
await new Promise ( resolve => { setTimeout ( resolve , 1000 ); });
const response = await fetch (
` ${ NODE_URL } /transactionStatus/ ${ transactionHash } ` );
if ( ! response . ok ) {
if ( 404 === response . status ) {
console . log ( ' Transaction status: unknown' );
continue ;
}
throw new Error ( `HTTP ${ response . status } ` );
}
const status = await response . json ();
console . log ( ' Transaction status:' , status . group );
if ( 'confirmed' === status . group ) {
console . log ( ` ${ label } confirmed in` , attempt , 'seconds' );
return ;
}
if ( 'failed' === status . group )
throw new Error ( ` ${ label } failed: ${ status . code } ` );
}
throw new Error ( ` ${ label } not confirmed after 60 seconds` );
}
const SIGNER_PRIVATE_KEY = process . env . SIGNER_PRIVATE_KEY || (
'0000000000000000000000000000000000000000000000000000000000000000' );
const signerKeyPair = new SymbolFacade . KeyPair (
new PrivateKey ( SIGNER_PRIVATE_KEY ));
const facade = new SymbolFacade ( 'testnet' );
const signerAddress = facade . network . publicKeyToAddress (
signerKeyPair . publicKey );
console . log ( 'Signer address:' , signerAddress . toString ());
try {
// Fetch recommended fees
const feePath = '/network/fees/transaction' ;
console . log ( 'Fetching recommended fees from' , feePath );
const feeResponse = await fetch ( ` ${ NODE_URL }${ feePath } ` );
const feeJSON = await feeResponse . json ();
const medianMultiplier = feeJSON . medianFeeMultiplier ;
const minimumMultiplier = feeJSON . minFeeMultiplier ;
const feeMultiplier = Math . max ( medianMultiplier , minimumMultiplier );
console . log ( ' Fee multiplier:' , feeMultiplier );
// --- CREATING MOSAIC DEFINITION ---
console . log ( '\n--- Creating mosaic definition ---' );
const nonce = Math . floor ( Date . now () / 1000 ) % 0x100000000 ;
console . log ( 'Mosaic nonce:' , nonce );
// Build the mosaic definition transaction
const definitionTx = facade . createTransactionFromTypedDescriptor (
new descriptors . MosaicDefinitionTransactionV1Descriptor (
new models . MosaicId ( 0n ),
new models . BlockDuration ( 0n ),
new models . MosaicNonce ( nonce ),
new models . MosaicFlags (
models . MosaicFlags . TRANSFERABLE . value |
models . MosaicFlags . RESTRICTABLE . value ),
2 ),
signerKeyPair . publicKey ,
feeMultiplier ,
2 * 60 * 60 );
const mosaicId = generateMosaicId ( signerAddress , nonce );
const mosaicIdHex = mosaicId . toString ( 16 )
. toUpperCase (). padStart ( 16 , '0' );
console . log ( `Mosaic ID: ${ mosaicId } (0x ${ mosaicIdHex } )` );
// Sign and generate final payload
const defSignature = facade . signTransaction (
signerKeyPair , definitionTx );
const defPayload = facade . transactionFactory . static . attachSignature (
definitionTx , defSignature );
console . log ( 'Built mosaic definition transaction:' );
console . dir ( definitionTx . toJson (), { colors : true });
// Announce and wait for confirmation
const definitionHash =
facade . hashTransaction ( definitionTx ). toString ();
console . log ( 'Transaction hash:' , definitionHash );
await announceTransaction ( defPayload , 'mosaic definition' );
await waitForConfirmation ( definitionHash , 'mosaic definition' );
// --- INCREASING MOSAIC SUPPLY ---
console . log ( '\n--- Increasing mosaic supply ---' );
const supplyTx = facade . createTransactionFromTypedDescriptor (
new descriptors . MosaicSupplyChangeTransactionV1Descriptor (
new models . UnresolvedMosaicId ( mosaicId ),
new models . Amount ( 100 _00n ),
models . MosaicSupplyChangeAction . INCREASE ),
signerKeyPair . publicKey ,
feeMultiplier ,
2 * 60 * 60 );
// Sign and generate final payload
const supSignature = facade . signTransaction (
signerKeyPair , supplyTx );
const supPayload = facade . transactionFactory . static . attachSignature (
supplyTx , supSignature );
console . log ( 'Built mosaic supply change transaction:' );
console . dir ( supplyTx . toJson (), { colors : true });
// Announce and wait for confirmation
const supplyHash = facade . hashTransaction ( supplyTx ). toString ();
console . log ( 'Transaction hash:' , supplyHash );
await announceTransaction ( supPayload , 'mosaic supply change' );
await waitForConfirmation ( supplyHash , 'mosaic supply change' );
// --- VERIFYING MOSAIC ---
console . log ( '\n--- Verifying mosaic ---' );
const mosaicPath = `/mosaics/ ${ mosaicIdHex } ` ;
console . log ( 'Fetching mosaic information from' , mosaicPath );
const mosaicResponse = await fetch ( ` ${ NODE_URL }${ mosaicPath } ` );
const mosaicJSON = await mosaicResponse . json ();
const mosaicInfo = mosaicJSON . mosaic ;
console . log ( 'Mosaic information:' );
console . log ( ' Mosaic ID:' , mosaicInfo . id );
console . log ( ' Supply:' , mosaicInfo . supply );
console . log ( ' Flags:' , mosaicInfo . flags );
console . log ( ' Divisibility:' , mosaicInfo . divisibility );
console . log ( ' Duration:' , mosaicInfo . duration );
} catch ( e ) {
console . error ( e . message );
}
Download source
//JAVA 21+
//DEPS org.symbol:symbol-sdk:3.3.1
import java.io.IOException ;
import java.net.URI ;
import java.net.http.HttpClient ;
import java.net.http.HttpRequest ;
import java.net.http.HttpResponse ;
import java.net.http.HttpResponse.BodyHandlers ;
import com.fasterxml.jackson.databind.JsonNode ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import org.symbol.sdk.CryptoTypes ;
import org.symbol.sdk.facade.SymbolFacade ;
import org.symbol.sdk.symbol.Address ;
import org.symbol.sdk.symbol.IdGenerator ;
import org.symbol.sdk.symbol.KeyPair ;
import org.symbol.sdk.symbol.SymbolTransactionFactory ;
import org.symbol.sdk.symbol.descriptors.* ;
import org.symbol.sdk.symbol.models.* ;
public final class CreateMosaic {
private static final ObjectMapper JSON_MAPPER = new ObjectMapper ();
private static final HttpClient HTTP_CLIENT =
HttpClient . newHttpClient ();
private final String nodeUrl = System . getenv (). getOrDefault (
"NODE_URL" , "https://reference.symboltest.net:3001" );
private final SymbolFacade facade = new SymbolFacade ( "testnet" );
private void announceTransaction (
final String payload ,
final String label
) throws IOException , InterruptedException {
System . out . printf ( "Announcing %s to /transactions%n" , label );
final HttpRequest request = HttpRequest . newBuilder (
URI . create ( nodeUrl + "/transactions" ))
. header ( "Content-Type" , "application/json" )
. PUT ( HttpRequest . BodyPublishers . ofString ( payload ))
. build ();
final HttpResponse < String > response = HTTP_CLIENT . send (
request , BodyHandlers . ofString ());
System . out . printf ( " Response: %s%n" , response . body ());
}
private void waitForConfirmation (
final String transactionHash ,
final String label
) throws IOException , InterruptedException {
System . out . printf ( "Waiting for %s confirmation...%n" , label );
for ( int attempt = 0 ; 60 > attempt ; ++ attempt ) {
Thread . sleep ( 1000 );
final String statusPath =
"/transactionStatus/" + transactionHash ;
final HttpRequest statusRequest = HttpRequest . newBuilder (
URI . create ( nodeUrl + statusPath )). GET (). build ();
final HttpResponse < String > statusResponse = HTTP_CLIENT
. send ( statusRequest , BodyHandlers . ofString ());
if ( 404 == statusResponse . statusCode ()) {
System . out . println ( " Transaction status: unknown" );
continue ;
}
if ( 2 != statusResponse . statusCode () / 100 )
throw new IOException (
"HTTP " + statusResponse . statusCode ());
final JsonNode status =
JSON_MAPPER . readTree ( statusResponse . body ());
final String group = status . get ( "group" ). asText ();
System . out . printf ( " Transaction status: %s%n" , group );
if ( "confirmed" . equals ( group )) {
System . out . printf ( "%s confirmed in %d seconds%n" ,
label , attempt );
return ;
}
if ( "failed" . equals ( group ))
throw new IOException ( String . format ( "%s failed: %s" ,
label , status . get ( "code" ). asText ()));
}
throw new IOException ( String . format (
"%s not confirmed after 60 seconds" , label ));
}
public static void main ( final String [] args ) {
try {
new CreateMosaic (). run ();
} catch ( final Exception ex ) {
System . out . println ( null == ex . getMessage ()
? ex . toString ()
: ex . getMessage ());
}
}
private void run () throws IOException , InterruptedException {
System . out . printf ( "Using node %s%n" , nodeUrl );
final String privateKeyString = System . getenv (). getOrDefault (
"SIGNER_PRIVATE_KEY" , "0" . repeat ( 64 ));
final KeyPair signerKeyPair = new KeyPair (
new CryptoTypes . PrivateKey ( privateKeyString ));
final Address signerAddress = facade . network . publicKeyToAddress (
signerKeyPair . getPublicKey ());
System . out . printf ( "Signer address: %s%n" , signerAddress );
// Fetch recommended fees
final String feePath = "/network/fees/transaction" ;
System . out . printf ( "Fetching recommended fees from %s%n" , feePath );
final HttpRequest feeRequest = HttpRequest . newBuilder (
URI . create ( nodeUrl + feePath )). GET (). build ();
final HttpResponse < String > feeResponse = HTTP_CLIENT . send (
feeRequest , BodyHandlers . ofString ());
final JsonNode feeJson = JSON_MAPPER . readTree ( feeResponse . body ());
final long feeMultiplier = Math . max (
feeJson . get ( "medianFeeMultiplier" ). asLong (),
feeJson . get ( "minFeeMultiplier" ). asLong ());
System . out . printf ( " Fee multiplier: %d%n" , feeMultiplier );
System . out . println ( "\n--- Creating mosaic definition ---" );
final long nonce = System . currentTimeMillis () & 0xFFFFFFFFL ;
System . out . printf ( "Mosaic nonce: %d%n" , nonce );
// Build the mosaic definition transaction
final Transaction definitionTx =
facade . createTransactionFromTypedDescriptor (
new MosaicDefinitionTransactionV1Descriptor (
new MosaicId ( 0 ),
new BlockDuration ( 0 ),
new MosaicNonce ( nonce ),
new MosaicFlags (
MosaicFlags . TRANSFERABLE . value |
MosaicFlags . RESTRICTABLE . value ),
2 ),
signerKeyPair . getPublicKey (),
feeMultiplier ,
2 * 60 * 60 );
final long mosaicId = IdGenerator . generateMosaicId (
signerAddress , nonce );
System . out . printf ( "Mosaic ID: %d (0x%016X)%n" ,
mosaicId , mosaicId );
// Sign and generate final payload
final CryptoTypes . Signature defSignature = facade . signTransaction (
signerKeyPair , definitionTx );
final String defPayload = SymbolTransactionFactory . attachSignature (
definitionTx , defSignature );
System . out . println ( "Built mosaic definition transaction:" );
System . out . println ( JSON_MAPPER . writerWithDefaultPrettyPrinter ()
. writeValueAsString ( definitionTx . toJson ()));
// Announce and wait for confirmation
final String definitionHash =
facade . hashTransaction ( definitionTx ). toString ();
System . out . printf ( "Transaction hash: %s%n" , definitionHash );
announceTransaction ( defPayload , "mosaic definition" );
waitForConfirmation ( definitionHash , "mosaic definition" );
System . out . println ( "\n--- Increasing mosaic supply ---" );
final Transaction supplyTx =
facade . createTransactionFromTypedDescriptor (
new MosaicSupplyChangeTransactionV1Descriptor (
new UnresolvedMosaicId ( mosaicId ),
new Amount ( 100_00 ),
MosaicSupplyChangeAction . INCREASE ),
signerKeyPair . getPublicKey (),
feeMultiplier ,
2 * 60 * 60 );
// Sign and generate final payload
final CryptoTypes . Signature supSignature = facade . signTransaction (
signerKeyPair , supplyTx );
final String supPayload = SymbolTransactionFactory . attachSignature (
supplyTx , supSignature );
System . out . println ( "Built mosaic supply change transaction:" );
System . out . println ( JSON_MAPPER . writerWithDefaultPrettyPrinter ()
. writeValueAsString ( supplyTx . toJson ()));
// Announce and wait for confirmation
final String supplyHash =
facade . hashTransaction ( supplyTx ). toString ();
System . out . printf ( "Transaction hash: %s%n" , supplyHash );
announceTransaction ( supPayload , "mosaic supply change" );
waitForConfirmation ( supplyHash , "mosaic supply change" );
System . out . println ( "\n--- Verifying mosaic ---" );
final String mosaicIdHex = "%016X" . formatted ( mosaicId );
final String mosaicPath = "/mosaics/" + mosaicIdHex ;
System . out . printf ( "Fetching mosaic information from %s%n" ,
mosaicPath );
final HttpRequest mosaicRequest = HttpRequest . newBuilder (
URI . create ( nodeUrl + mosaicPath )). GET (). build ();
final HttpResponse < String > mosaicResponse = HTTP_CLIENT . send (
mosaicRequest , BodyHandlers . ofString ());
final JsonNode mosaicInfo = JSON_MAPPER . readTree (
mosaicResponse . body ()). get ( "mosaic" );
System . out . println ( "Mosaic information:" );
System . out . printf ( " Mosaic ID: %s%n" ,
mosaicInfo . get ( "id" ). asText ());
System . out . printf ( " Supply: %s%n" ,
mosaicInfo . get ( "supply" ). asText ());
System . out . printf ( " Flags: %s%n" ,
mosaicInfo . get ( "flags" ). asText ());
System . out . printf ( " Divisibility: %s%n" ,
mosaicInfo . get ( "divisibility" ). asText ());
System . out . printf ( " Duration: %s%n" ,
mosaicInfo . get ( "duration" ). asText ());
}
}
Download source
コード解説
モザイクの作成には、2つのトランザクションをアナウンスする必要があります。
モザイクとそのプロパティを登録するための モザイク定義 トランザクション。
初期ユニットをミントするための モザイク供給量変更 トランザクション。
アカウントの設定
このスニペットは、署名者の 秘密鍵 を SIGNER_PRIVATE_KEY 環境変数から読み取ります。設定されていない場合はデフォルトのテストキーが使用されます。
署名者の アドレス は 公開鍵 から派生します。
このアカウントが作成されたモザイクを所有することになります。
推奨手数料の取得
転送トランザクション チュートリアルで説明されているプロセスに従い、推奨手数料を /network/fees/transaction GET から取得します。
モザイクノンスの生成
各モザイクは ノンス によって識別されます。ノンスは、同じアカウントによって作成されたモザイクの、ローカルで一意な識別子として機能する任意の32ビット無符号整数(0 から 4,294,967,295)です。
モザイクID は、 IdGenerator.generate_mosaic_id generateMosaicId IdGenerator.generateMosaicId を使用して所有者のアドレスとノンスから決定論的に派生するため、一意のノンスごとに異なるモザイクが生成されます。
このチュートリアルでのノンスの選択
このチュートリアルでは、実行ごとに一意のモザイクが作成されるように、現在のタイムスタンプをノンスとして使用しています。
& 0xFFFFFFFF ビットマスクは、値を32ビットに収まるように切り詰めます。
実際には、同じアカウントがそのノンスをまだ使用していない限り、どのような値でも機能します。
モザイク定義トランザクションの構築
# Build the mosaic definition transaction
definition_tx = facade . create_transaction_from_descriptor (
{
'type' : 'mosaic_definition_transaction_v1' ,
'duration' : 0 ,
'divisibility' : 2 ,
'nonce' : nonce ,
'flags' : 'transferable restrictable'
},
signer_key_pair . public_key ,
fee_multiplier ,
2 * 60 * 60 )
mosaic_id = generate_mosaic_id ( signer_address , nonce )
print ( f 'Mosaic ID: { mosaic_id } (0x { mosaic_id : 016X } )' )
// Build the mosaic definition transaction
const definitionTx = facade . createTransactionFromTypedDescriptor (
new descriptors . MosaicDefinitionTransactionV1Descriptor (
new models . MosaicId ( 0n ),
new models . BlockDuration ( 0n ),
new models . MosaicNonce ( nonce ),
new models . MosaicFlags (
models . MosaicFlags . TRANSFERABLE . value |
models . MosaicFlags . RESTRICTABLE . value ),
2 ),
signerKeyPair . publicKey ,
feeMultiplier ,
2 * 60 * 60 );
const mosaicId = generateMosaicId ( signerAddress , nonce );
const mosaicIdHex = mosaicId . toString ( 16 )
. toUpperCase (). padStart ( 16 , '0' );
console . log ( `Mosaic ID: ${ mosaicId } (0x ${ mosaicIdHex } )` );
// Build the mosaic definition transaction
final Transaction definitionTx =
facade . createTransactionFromTypedDescriptor (
new MosaicDefinitionTransactionV1Descriptor (
new MosaicId ( 0 ),
new BlockDuration ( 0 ),
new MosaicNonce ( nonce ),
new MosaicFlags (
MosaicFlags . TRANSFERABLE . value |
MosaicFlags . RESTRICTABLE . value ),
2 ),
signerKeyPair . getPublicKey (),
feeMultiplier ,
2 * 60 * 60 );
final long mosaicId = IdGenerator . generateMosaicId (
signerAddress , nonce );
System . out . printf ( "Mosaic ID: %d (0x%016X)%n" ,
mosaicId , mosaicId );
モザイク定義トランザクションは、新しいモザイクをネットワークに登録します。
SymbolFacade.create_transaction_from_descriptor SymbolFacade.createTransactionFromTypedDescriptor SymbolFacade.createTransactionFromTypedDescriptor に渡す署名者が、作成されたモザイクの所有者になります。
トランザクションのディスクリプタには、以下が含まれます。
レンタル手数料
標準の トランザクション手数料 に加えて、モザイクの作成には XYM で支払う一回限りのレンタル手数料が必要です。
トランザクション手数料とは異なり、レンタル手数料はトランザクションリクエストには 含まれません 。
モザイク定義トランザクションが承認されると、ネットワークによって署名者のアカウントから自動的に差し引かれます。
レンタル手数料の額は、 /network/fees/rental GET エンドポイント( effectiveMosaicRentalFee プロパティ)から照会できます。
モザイク定義の送信
# Sign and generate final payload
signature = facade . sign_transaction ( signer_key_pair , definition_tx )
json_payload = facade . transaction_factory . attach_signature (
definition_tx , signature )
print ( 'Built mosaic definition transaction:' )
print ( json . dumps ( definition_tx . to_json (), indent = 2 ))
# Announce and wait for confirmation
definition_hash = facade . hash_transaction ( definition_tx )
print ( f 'Transaction hash: { definition_hash } ' )
announce_transaction ( json_payload , 'mosaic definition' )
wait_for_confirmation ( definition_hash , 'mosaic definition' )
// Sign and generate final payload
const defSignature = facade . signTransaction (
signerKeyPair , definitionTx );
const defPayload = facade . transactionFactory . static . attachSignature (
definitionTx , defSignature );
console . log ( 'Built mosaic definition transaction:' );
console . dir ( definitionTx . toJson (), { colors : true });
// Announce and wait for confirmation
const definitionHash =
facade . hashTransaction ( definitionTx ). toString ();
console . log ( 'Transaction hash:' , definitionHash );
await announceTransaction ( defPayload , 'mosaic definition' );
await waitForConfirmation ( definitionHash , 'mosaic definition' );
// Sign and generate final payload
final CryptoTypes . Signature defSignature = facade . signTransaction (
signerKeyPair , definitionTx );
final String defPayload = SymbolTransactionFactory . attachSignature (
definitionTx , defSignature );
System . out . println ( "Built mosaic definition transaction:" );
System . out . println ( JSON_MAPPER . writerWithDefaultPrettyPrinter ()
. writeValueAsString ( definitionTx . toJson ()));
// Announce and wait for confirmation
final String definitionHash =
facade . hashTransaction ( definitionTx ). toString ();
System . out . printf ( "Transaction hash: %s%n" , definitionHash );
announceTransaction ( defPayload , "mosaic definition" );
waitForConfirmation ( definitionHash , "mosaic definition" );
モザイク定義トランザクションは、 転送トランザクション チュートリアルと同じプロセスに従って署名され、アナウンスされます。
コードはその後、ステータスが confirmed に変わるまで /transactionStatus/{hash} GET エンドポイントをポーリングして、トランザクションが承認されるのを待ちます。
モザイク供給量変更トランザクションの構築
supply_tx = facade . create_transaction_from_descriptor (
{
'type' : 'mosaic_supply_change_transaction_v1' ,
'mosaic_id' : mosaic_id ,
'action' : 'increase' ,
'delta' : 100_00
},
signer_key_pair . public_key ,
fee_multiplier ,
2 * 60 * 60 )
const supplyTx = facade . createTransactionFromTypedDescriptor (
new descriptors . MosaicSupplyChangeTransactionV1Descriptor (
new models . UnresolvedMosaicId ( mosaicId ),
new models . Amount ( 100 _00n ),
models . MosaicSupplyChangeAction . INCREASE ),
signerKeyPair . publicKey ,
feeMultiplier ,
2 * 60 * 60 );
final Transaction supplyTx =
facade . createTransactionFromTypedDescriptor (
new MosaicSupplyChangeTransactionV1Descriptor (
new UnresolvedMosaicId ( mosaicId ),
new Amount ( 100_00 ),
MosaicSupplyChangeAction . INCREASE ),
signerKeyPair . getPublicKey (),
feeMultiplier ,
2 * 60 * 60 );
モザイク定義が承認されると、2番目のトランザクションでモザイクの供給量を増加させます。
SymbolFacade.create_transaction_from_descriptor SymbolFacade.createTransactionFromTypedDescriptor SymbolFacade.createTransactionFromTypedDescriptor に渡す署名者は、変更対象のモザイクの所有者である必要があります。
トランザクションのディスクリプタには、以下が含まれます。
供給量変更の送信
# Sign and generate final payload
signature = facade . sign_transaction ( signer_key_pair , supply_tx )
json_payload = facade . transaction_factory . attach_signature (
supply_tx , signature )
print (
'Built mosaic supply change transaction:' )
print ( json . dumps ( supply_tx . to_json (), indent = 2 ))
# Announce and wait for confirmation
supply_hash = facade . hash_transaction ( supply_tx )
print ( f 'Transaction hash: { supply_hash } ' )
announce_transaction ( json_payload , 'mosaic supply change' )
wait_for_confirmation ( supply_hash , 'mosaic supply change' )
// Sign and generate final payload
const supSignature = facade . signTransaction (
signerKeyPair , supplyTx );
const supPayload = facade . transactionFactory . static . attachSignature (
supplyTx , supSignature );
console . log ( 'Built mosaic supply change transaction:' );
console . dir ( supplyTx . toJson (), { colors : true });
// Announce and wait for confirmation
const supplyHash = facade . hashTransaction ( supplyTx ). toString ();
console . log ( 'Transaction hash:' , supplyHash );
await announceTransaction ( supPayload , 'mosaic supply change' );
await waitForConfirmation ( supplyHash , 'mosaic supply change' );
// Sign and generate final payload
final CryptoTypes . Signature supSignature = facade . signTransaction (
signerKeyPair , supplyTx );
final String supPayload = SymbolTransactionFactory . attachSignature (
supplyTx , supSignature );
System . out . println ( "Built mosaic supply change transaction:" );
System . out . println ( JSON_MAPPER . writerWithDefaultPrettyPrinter ()
. writeValueAsString ( supplyTx . toJson ()));
// Announce and wait for confirmation
final String supplyHash =
facade . hashTransaction ( supplyTx ). toString ();
System . out . printf ( "Transaction hash: %s%n" , supplyHash );
announceTransaction ( supPayload , "mosaic supply change" );
waitForConfirmation ( supplyHash , "mosaic supply change" );
モザイク供給量変更トランザクションは、モザイク定義トランザクションと同じプロセスに従って署名され、アナウンスされます。
両方のトランザクションの組み合わせ
定義と供給量変更を2つの別々のトランザクションとしてアナウンスする代わりに、単一の コンプリートアグリゲートトランザクション 内でまとめて送信することができます。
これにより、両方の操作が同じブロック内でアトミック(不可分)に承認されることが保証されます。
supply_mutable フラグがなくても、所有者が供給量全体を保持している限り、供給量の変更は許可されます。ユニットがいずれかの他のアカウントに配布されると、供給量は恒久的に固定されます。
モザイクの取得
mosaic_id_hex = f ' { mosaic_id : 016X } '
mosaic_path = f '/mosaics/ { mosaic_id_hex } '
print ( f 'Fetching mosaic information from { mosaic_path } ' )
with urllib . request . urlopen ( f ' { NODE_URL }{ mosaic_path } ' ) as response :
response_json = json . loads ( response . read () . decode ())
mosaic_info = response_json [ 'mosaic' ]
print ( 'Mosaic information:' )
print ( f ' Mosaic ID: { mosaic_info [ "id" ] } ' )
print ( f ' Supply: { mosaic_info [ "supply" ] } ' )
print ( f ' Flags: { mosaic_info [ "flags" ] } ' )
print ( f ' Divisibility: { mosaic_info [ "divisibility" ] } ' )
print ( f ' Duration: { mosaic_info [ "duration" ] } ' )
const mosaicPath = `/mosaics/ ${ mosaicIdHex } ` ;
console . log ( 'Fetching mosaic information from' , mosaicPath );
const mosaicResponse = await fetch ( ` ${ NODE_URL }${ mosaicPath } ` );
const mosaicJSON = await mosaicResponse . json ();
const mosaicInfo = mosaicJSON . mosaic ;
console . log ( 'Mosaic information:' );
console . log ( ' Mosaic ID:' , mosaicInfo . id );
console . log ( ' Supply:' , mosaicInfo . supply );
console . log ( ' Flags:' , mosaicInfo . flags );
console . log ( ' Divisibility:' , mosaicInfo . divisibility );
console . log ( ' Duration:' , mosaicInfo . duration );
final String mosaicIdHex = "%016X" . formatted ( mosaicId );
final String mosaicPath = "/mosaics/" + mosaicIdHex ;
System . out . printf ( "Fetching mosaic information from %s%n" ,
mosaicPath );
final HttpRequest mosaicRequest = HttpRequest . newBuilder (
URI . create ( nodeUrl + mosaicPath )). GET (). build ();
final HttpResponse < String > mosaicResponse = HTTP_CLIENT . send (
mosaicRequest , BodyHandlers . ofString ());
final JsonNode mosaicInfo = JSON_MAPPER . readTree (
mosaicResponse . body ()). get ( "mosaic" );
System . out . println ( "Mosaic information:" );
System . out . printf ( " Mosaic ID: %s%n" ,
mosaicInfo . get ( "id" ). asText ());
System . out . printf ( " Supply: %s%n" ,
mosaicInfo . get ( "supply" ). asText ());
System . out . printf ( " Flags: %s%n" ,
mosaicInfo . get ( "flags" ). asText ());
System . out . printf ( " Divisibility: %s%n" ,
mosaicInfo . get ( "divisibility" ). asText ());
System . out . printf ( " Duration: %s%n" ,
mosaicInfo . get ( "duration" ). asText ());
モザイクが正常に作成されたことを確認するために、コードは /mosaics/{mosaicId} GET エンドポイントを使用してネットワークからモザイクを取得し、そのプロパティを表示します。
レスポンスが成功すれば、期待通りの供給量と可分性を持ってネットワーク上にモザイクが存在することが確認されます。
出力
以下に示す出力は、プログラムの典型的な実行結果に対応しています。
Using node https://reference.symboltest.net:3001
Signer address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
Fetching recommended fees from /network/fees/transaction
Fee multiplier: 100
--- Creating mosaic definition ---
Mosaic nonce: 1770754477
Mosaic ID: 8318126551268698739 (0x736FEC06ED1DAA73)
Built mosaic definition transaction:
{
"signature": "6516FB17F162075795E8A4578595DE4745A57B151A6A6ACABF613C1ADF94DC36AF13F661E9FC356723A1F653D2ECC434E514F891A7D16502825431FE5AC17F06",
"signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
"version": 1,
"network": 152,
"type": 16717,
"fee": "15000",
"deadline": "103511212049",
"id": "8318126551268698739",
"duration": "0",
"nonce": 1770754477,
"flags": 6,
"divisibility": 2
}
Transaction hash: 959C4FDE753700E21959CB23E46EE761937A3AFEAFB40DBD9ADFBEE2D1C85F8B
Announcing mosaic definition to /transactions
Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for mosaic definition confirmation...
Transaction status: unconfirmed
Transaction status: unconfirmed
Transaction status: confirmed
mosaic definition confirmed in 12 seconds
--- Increasing mosaic supply ---
Built mosaic supply change transaction:
{
"signature": "9704D30D6B060CB28A5A8DA3BAC40B7D02D878199C32D57FA70B6EB213735677BF7380F14A1A9B04B7DEA806D55A379CF20BAC3BDA24D16094DF2F97917A5605",
"signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
"version": 1,
"network": 152,
"type": 16973,
"fee": "14500",
"deadline": "103511212049",
"mosaic_id": "8318126551268698739",
"delta": "10000",
"action": 1
}
Transaction hash: E4E002C9E4536666E47E4B98DB7307FF5715C4BD8C4579D8AD67C9CBCECC2CD2
Announcing mosaic supply change to /transactions
Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for mosaic supply change confirmation...
Transaction status: unconfirmed
Transaction status: confirmed
mosaic supply change confirmed in 9 seconds
--- Verifying mosaic ---
Fetching mosaic information from /mosaics/736FEC06ED1DAA73
Mosaic information:
Mosaic ID: 736FEC06ED1DAA73
Supply: 10000
Flags: 6
Divisibility: 2
Duration: 0
出力の主なポイント:
モザイクID (8行目): ノンスが署名者のアドレスと組み合わされ、モザイクID 0x736FEC06ED1DAA73 が派生します。
手数料 (16行目): 0.015 XYM のトランザクション手数料は、トランザクションサイズに手数料倍率を乗じて計算されます。 レンタル手数料 は、トランザクションが承認された際にネットワークによって別途差し引かれます。
モザイクID (18行目): id フィールドは、ノンスと署名者のアドレスから SDK によって自動的に計算され、8行目に印刷された値と一致します。
モザイクプロパティ (19、21-22行目): フラグはビットマスクとして保存され、各フラグは1ビットを占めます。 supply_mutable (1)、 transferable (2)、 restrictable (4)、 revokable (8) です。
値 6 は、 transferable (2) + restrictable (4) と等しくなります。可分性は 2 で、有効期間 0 はモザイクが期限切れにならないことを意味します。
供給量デルタ (44行目): デルタ 10000 絶対単位は、モザイクの可分性が 2 であるため、 100.00 全体単位を表します。
検証されたプロパティ (58-62行目): モザイクがネットワークから取得され、期待通りの供給量、フラグ、可分性、有効期間が確認されました。
出力に印刷されたトランザクション ハッシュ を使用して、 Symbol Testnet Explorer でトランザクションを検索できます。
結論
このチュートリアルでは、以下の方法を説明しました。
次のステップ
モザイクを作成したので、以下のことができます。