Symbol from NEMではエンタープライズ分野で人気のあるJava言語でも使用することができます。
今回はJavaでSymbol送金を体験してみましょう。
まず、公式の案内通りにGradleの準備をします(Gradle 7.0 以上)
ここで
dependencies {
compile "io.nem:symbol-sdk-vertx-client"
}
とありますが、これでは動きません。
implementation 'io.nem:symbol-sdk-vertx-client:1.0.0'
と読み替えてください。
gradle run
が実行できるようになったらApp.javaを書き換えていきます。
基本プログラム
package symbol_test;
public class App {
public static void main(String[] args) throws Exception {
run();
}
public String getGreeting() {
return "Hello Symbol!";
}
private static void run() throws Exception {
Thread.sleep(1000);
run();
}
}
これが基本フォーマットになります。
public static void main
からプログラムが開始され runで強制終了されるまでループします。
送金プログラムだけの場合はループは必要ありませんが、着金を検知するためにループで待機しています。
import
今回使用するライブラリです。
import java.time.Duration;
import java.math.BigInteger;
import java.util.Collections;
import io.nem.symbol.sdk.api.Listener;
import io.nem.symbol.sdk.api.RepositoryFactory;
import io.nem.symbol.sdk.api.TransactionRepository;
import io.nem.symbol.sdk.model.account.Address;
import io.nem.symbol.sdk.model.account.Account;
import io.nem.symbol.sdk.model.mosaic.Mosaic;
import io.nem.symbol.sdk.model.mosaic.MosaicId;
import io.nem.symbol.sdk.model.message.PlainMessage;
import io.nem.symbol.sdk.model.network.NetworkType;
import io.nem.symbol.sdk.model.transaction.Deadline;
import io.nem.symbol.sdk.model.transaction.Transaction;
import io.nem.symbol.sdk.model.transaction.SignedTransaction;
import io.nem.symbol.sdk.model.transaction.TransferTransaction;
import io.nem.symbol.sdk.model.transaction.TransferTransactionFactory;
import io.nem.symbol.sdk.infrastructure.vertx.RepositoryFactoryVertxImpl;
python版では対話式に都度ライブラリを追加していきましたが、
Javaでは最初に宣言しておきます。
リポジトリ生成
RepositoryFactory repo = new RepositoryFactoryVertxImpl(
"http://ngl-dual-101.testnet.symboldev.network:3000"
);
接続するノードを指定してレポジトリを生成します。
アカウント生成
Account alice = Account.createFromPrivateKey(
"896E43895B908AF5847ECCB2645543751D94BD87E71058B003417FED512****",
NetworkType.TEST_NET
);
System.out.printf("Alice address is: %s \n",alice.getAddress().plain());
Account bob = Account.generateNewAccount(NetworkType.TEST_NET);
System.out.printf("Bob address is: %s \n",bob.getAddress().plain());
送金者Aliceと受信者Bobを生成します。送信者は残高を持つ秘密鍵から生成。Bobはランダムに生成しました。
トークン定義
BigInteger amount = BigInteger.valueOf(1);
Mosaic mosaic = new Mosaic(
new MosaicId("091F837E059AE13C"),
amount.multiply(
BigInteger.valueOf(10).pow(6)
)
);
送金するトークンを定義します。
テストネットのXYMはID:091F837E059AE13C 可分性:6で定義されています。
公式ドキュメントは古いテストネットのIDで解説されているのでご注意ください。
トランザクション生成
TransferTransaction tx = TransferTransactionFactory.create(
NetworkType.TEST_NET,
Deadline.create(repo.getEpochAdjustment().toFuture().get()),
bob.getAddress(),
Collections.singletonList(mosaic)
).message(
PlainMessage.create("This is a test message")
).maxFee(BigInteger.valueOf(2000000)
).build();
送金トランザクションを生成します。
このあたりは公式ドキュメントの情報が古いので、少し変更が必要です。
- Deadlineを指定してください(引数にはネットワークのエポックタイムの指定が必要です)。
- メッセージはcreateの引数ではなく、メソッドチェーンで追加していきます。
署名とアナウンス
String generationHash = repo.getGenerationHash().toFuture().get();
SignedTransaction signedTx = alice.sign(tx, generationHash);
System.out.printf("SignedTransaction is: %s ",signedTx.getHash());
TransactionRepository txRepo = repo.createTransactionRepository();
txRepo.announce(signedTx).toFuture().get();
作成したトランザクションをAliceで署名してネットワークにアナウンスします。
着金検知
Listener listener = repo.createListener();
listener.open().get();
listener.confirmed(bob.getAddress())
.subscribe(
(notice) -> { System.out.println(notice.getType().toString());},
(e) -> { System.out.println(e);}
);
リスナークラスを利用してBobへの着金を検知します。
Listener.confirmedで承認されたトランザクションが検知できます。
この書き方はVistiel Archさんの記事を参考にさせていただきました。
また、nabe3さんがJava版マイクラでXYMを送金するプラグインを実装した記事を公開されています。
最後に全ソースコードを載せておきます。
ぜひみなさん、お試しください!
package symbol_test;
import java.time.Duration;
import java.math.BigInteger;
import java.util.Collections;
import io.nem.symbol.sdk.api.Listener;
import io.nem.symbol.sdk.api.RepositoryFactory;
import io.nem.symbol.sdk.api.TransactionRepository;
import io.nem.symbol.sdk.model.account.Address;
import io.nem.symbol.sdk.model.account.Account;
import io.nem.symbol.sdk.model.mosaic.Mosaic;
import io.nem.symbol.sdk.model.mosaic.MosaicId;
import io.nem.symbol.sdk.model.message.PlainMessage;
import io.nem.symbol.sdk.model.network.NetworkType;
import io.nem.symbol.sdk.model.transaction.Deadline;
import io.nem.symbol.sdk.model.transaction.Transaction;
import io.nem.symbol.sdk.model.transaction.SignedTransaction;
import io.nem.symbol.sdk.model.transaction.TransferTransaction;
import io.nem.symbol.sdk.model.transaction.TransferTransactionFactory;
import io.nem.symbol.sdk.infrastructure.vertx.RepositoryFactoryVertxImpl;
public class App {
public static void main(String[] args) throws Exception {
RepositoryFactory repo = new RepositoryFactoryVertxImpl(
"http://ngl-dual-101.testnet.symboldev.network:3000"
);
Account alice = Account.createFromPrivateKey(
"896E43895B908AF5847ECCB2645543751D94BD87E71058B003417FED512314AE",
NetworkType.TEST_NET
);
System.out.printf("Alice address is: %s \n",alice.getAddress().plain());
Account bob = Account.generateNewAccount(NetworkType.TEST_NET);
System.out.printf("Bob address is: %s \n",bob.getAddress().plain());
BigInteger amount = BigInteger.valueOf(1);
Mosaic mosaic = new Mosaic(
new MosaicId("091F837E059AE13C"),
amount.multiply(
BigInteger.valueOf(10).pow(6)
)
);
TransferTransaction tx = TransferTransactionFactory.create(
NetworkType.TEST_NET,
Deadline.create(repo.getEpochAdjustment().toFuture().get()),
bob.getAddress(),
Collections.singletonList(mosaic)
).message(
PlainMessage.create("This is a test message")
).maxFee(BigInteger.valueOf(2000000)
).build();
String generationHash = repo.getGenerationHash().toFuture().get();
SignedTransaction signedTx = alice.sign(tx, generationHash);
System.out.printf("SignedTransaction is: %s ",signedTx.getHash());
TransactionRepository txRepo = repo.createTransactionRepository();
txRepo.announce(signedTx).toFuture().get();
Listener listener = repo.createListener();
listener.open().get();
listener.confirmed(bob.getAddress())
.subscribe(
(notice) -> { System.out.println(notice.getType().toString());},
(e) -> { System.out.println(e);}
);
run();
}
public String getGreeting() {
return "Hello Symbol!";
}
private static void run() throws Exception {
Thread.sleep(1000);
run();
}
}