R3のデベロッパーエンジニアAnthony Nixonにより書かれた記事をTaira Nakamuraが日本語訳しました。
2020年5月21日
四半期リリースで新たなToken SDKが実装された。洗練されたAPIと2つの新しいtokenbuilderという形で、Java開発者にとってうれしい機能が追加されました。この投稿では、これらの変更点のいくつかを取り上げ、Cordaでデジタルアセットを使用することがこれまでになく簡単にできる例を示します。
Spaceships sample projectで提供されているCode snippetsとそのサンプルはこちらのリンクから入手可能です。
まず、始める前に、Cordaでトークンを発行するプロセスを簡単にまとめます。 発行には、fungibleとnon-fungibleの2種類があります。たとえば、代替可能なトークンは、分割や統合のできるトークンで、ペソや米ドルなどの法定通貨、または株のシェアがあげられます。non-fungible tokenは、分割できず、全体として発行、移動、引き換えられるものです。例として家や自転車など、現実世界でユニークなものを表現するのに役立ちます(Token SDKの完全な要約と無料のCordaトレーニングについては、こちらをご参照ください。)。
トークンの各タイプはビルディングブロックで構成されており、開発者はより柔軟に台帳上のデジタルアセットを表現することができます。
Fungible tokenは次の要素で構成されています。
Non-fungible tokenは次のように構成されています。
これらの各コンポーネントは、発行前にfinal tokenを作成するために定義及びインスタンス化する必要があるオブジェクトです。なれるととても簡単ですが、以前は少し面倒でした。
以下はもとのToken-SDKで作成されたfungible tokenの例です。
TokenType myToken = new TokenType("My Token", 2);
IssuedTokenType issuedMyToken = new IssuedTokenType(issuingParty, myToken);
Amount<IssuedTokenType> amountMyIssuedToken = new Amount<>(100, issuedMyToken);
FungibleToken fungibleMyToken = new FungibleToken(amountMyIssuedToken, holder);
現在はすごく簡単に発行できるようになっています。
お金と通貨のユーティリティ
Cordaで作成する最も一般的なToken Typesの1つは、実際のISO標準の法定通貨の表現です。 Corda Token SDKにこれらのトークンを迅速にインスタンス化するためのユーティリティクラスが含まれていることに気付かない人も多いと思います。[Source code]
MoneyUtilitiesクラスは主要なフィアット通貨とデジタル通貨に対して正しく定義されたTokenTypesとAmouts of TokenTypesを取得します。これはFiatCurrencyおよびDigitalCurrencyの定義を利用しています。
import com.r3.corda.lib.tokens.money.MoneyUtilities;
// Instantiating currencies and amounts
TokenType usdTokenType = MoneyUtilities.getUSD();
TokenType rippleTokenType = MoneyUtilities.getXRP();
Amount<TokenType> amountAUD = MoneyUtilities.getAUD(100.22);
これらの標準通貨がトークン発行にどのように供給されるかについての基本的なデモについてはこちらをご参照ください。
Javaを使ってAmountをハンドリングする
前のコードブロックから、MoneyUtilitiesの呼び出しでAmount <TokenType>のインスタンスをすばやく生成できたと思いますが、独自でカスタムをするTokenTypes、または動的TokenTypeについては生成できたでしょうか?これらを生成するために、AmountUtilitiesを利用します。
最も単純な形式では、任意のTokenTypeの量をすばやく返すことができます。
import com.r3.corda.lib.tokens.contracts.utilities.AmountUtilities;
// Creating an amount of customTokenType
double amount = 102.00;
TokenType customTokenType = new TokenType("Bob Token", 2);
Amount<TokenType> myAmount = AmountUtilities.amount(newValue, customTokenType);
より発展的な方法として、fixed exchange ratesを用いてTokenTypeを別のTokenTypeに換金するサンプルについては こちらをご参照ください。[Source code]
/**
* exchangeCurrency calculates an amount back in targetCurrency that is fair exchange with an itemCurrency
* This allows a buyer to know how much of his held currency to give to a seller to satisfy the price.
* @param amount
* @param targetCurrency
* @return
*/
static Amount<TokenType> exchangeCurrency(Amount<TokenType> amount, TokenType targetCurrency) {
int itemCurrFractionDigits = amount.getToken().getFractionDigits();
double newValue = (amount.getQuantity()/Math.pow(10,itemCurrFractionDigits)) * (rates.get(amount.getToken().getTokenIdentifier()) / rates.get(targetCurrency.getTokenIdentifier()));
return AmountUtilities.amount(newValue, targetCurrency);
}
Amountsを作るだけよりもAmountUtilitiesは繰り返し合算可能な関数の機能を持っています 。合算したい金額がたくさんある?。問題はありません。
List<Amount<TokenTypes>> myAmounts = ...;
Amount<TokenType> mySum = AmountUtilities.sumTokensOrThrow(myAmounts);
Java Token Builders
基礎的な通貨TokenTypesは理解できましたか?心強いヘルメットをかぶって、Java開発者にとってこのリリースで最大の難関を始めましょう!新しいFungibleTokenBuilderとNon-FungibleTokenBuilderクラスへすすみます。
完成されたトークンの構成方法をどのように説明したか覚えていますか(上の図を参照)?構築は多段階なプロセスでした。
Kotlinでは、Token SDKの最初のリリース以降、言語の修正内記法を利用して、次のような構文でトークンを迅速に構築できました。
val myFungibleToken = 10.GBP issuedBy issuingParty heldBy holder
しかし、Javaに類似するものは何もありませんでした。今までは。
TokenBuilderクラスはJava開発者にとっては使い慣れたビルダーパラダイムを使用して、この呼び出しを複製化しています。
FungibleTokenを作っていきましょう。
Party issuingParty = ...;
Party holder = ...;
FungibleToken token = new FungibleTokenBuilder()
.ofTokenType(MoneyUtilities.getGBP())
.withAmount(10)
.issuedBy(issuingParty)
.heldBy(holder)
.buildFungibleToken();
Let’s build a NonFungibleToken:
Party manufacturer = ...;
Party owner = ...;
NonFungibleToken token = new NonFungibleTokenBuilder()
.ofTokenType(new BicycleTokenType())
.issuedBy(manufacturer)
.heldBy(owner)
.buildNonFungibleToken();
とても読みやすくて簡潔ですね。さらに、ビルダーは構成が正しいかを確認してくれるので、トークン作成でステージを逃す心配はありません。
ビルダーの使用方法の詳細については、spaceshipsのreference sampleを参照してください。これらのビルダーを使用して、fungibleおよびnon-fungibleなspace craftをトークン化します。[Source code]
Flowをよりフレキシブルにする
Javaで簡単に構築できるのはトークンだけではありません。Flowにおいても力を発揮します。トランザクションを作るところから、アセットのクエリと操作をするところまでカバーしています。ここに利用可能なツールをいくつかご紹介したいと思います。
NotaryUtilities:NotaryはCordaのワークフローにおいて、根幹をなす部分です。(もし、復習が必要であればこちらをご参照ください。)。Token SDKには、あなたのトランザクションを承認するNotaryNotaryを、アルゴリズムを用いて決める機能を持ったユーティリティが含まれています。もしあなたがCordaを始めたばかりなら、次のようなコードに慣れ親しんでいるかもしれません。
getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
このコードはネットワーク上で利用可能な最初のNotaryを得ることができます。NotaryUtilitiesクラスでは推奨されたNotaryを定義することができます。デフォルトでは一番はじめのNotaryですが、静的、アルゴリズム、ランダムに選択するを選んでオーバーライドすることができます。(注:Notary選択の作製は発行時しか行えません。通常、ライフサイクル全体を通じて、同じNotaryに結びつける必要があります。したがって、後続の操作のために、Notaryからinput-stateを切り離します。)
トークンのクエリ ー 台帳のうえには何があるでしょうか?
CordaはVault(またの名をledger)に対するクエリのパターンが用意されています。(復習はこちらのリンクから)。基本的なことはすべて適用されますが、トークンはとても標準化され、定義されているため、QueryUtilitiesを介してJavaで必要な情報を素早く簡単に提供しています。
QueryUtilitiesを用いてトークン上でクエリが利用可能
上記のように、ノードの観点からFlowで呼び出されると、FungibleまたはNonFungibleの状態、量、およびQueryCriteriaオブジェクトをすばやく取得できます(より複雑なqueryBy操作を構築するため)。 シンプルで簡単です。 spaceshipサンプルから取得した以下のcode-snippetは、保有するSpaceShipTokenTypeの量とその値(プロパティ)を相手方に送信します。[Source code]
@Suspendable
@Override
public Void call() throws FlowException {
// receive request for value of the given shipId
String shipId = counterpartySession.receive(String.class).unwrap(it -> it);
UUID shipUUID = UUID.fromString(shipId);
SpaceshipTokenType spaceshipTokenType = FlowHelpers.uuidToSpaceShipTokenType(getServiceHub().getVaultService(), shipUUID);
Amount<TokenType> amountOfSpaceShipTokens = QueryUtilities.tokenBalance(getServiceHub().getVaultService(), spaceshipTokenType.toPointer());
counterpartySession.send(new Pair<>(amountOfSpaceShipTokens, spaceshipTokenType.getValue()));
return null;
}
トークン選択とトランザクションを構築する
Token SDKベースは、Javaの姉妹言語Kotlinでプログラムされています。これには多くの利点があり2つは100%相互運用可能です。SDKの初期バージョンを使用すると、提供されたFlowによってトークンの発行、移動、または引き換えが楽しいものであることが理解できたはずです。 たとえば、私は Ashutoshにいくつかのトークンを1行で送信できます。
new MoveFungibleTokens(new PartyAndAmount<>(ashutosh, amount)));
しかし、もっと複雑なトランザクション(例えば要素をTransction Builderに手動で加える )ことになると、デフォルトのパラメーターがオーバーロードできない事実にイライラしていたかもしれません。
tokenSelection.generateMove(getRunId().getUuid(), Collections.singletonList(sendingPartyAndAmount), getOurIdentity(), null
ーあれ、()がいっぱいみれらます。どうして引数がnullばかりなんでしょう?
その答えはすごくシンプルでConstructorとfunction signatureは今はオーバーロードできるのです。もう一度試してみましょう。
tokenSelection.generateMove(Collections.singletonList(sendingPartyAndAmount), getOurIdentity());
あなたはすでに追加されたパラメーターすべてにアクセスすることができます。
飛び込む準備はいい?spaceshipの例でatomic性(単一トランザクション)と支払いの交換について確認してください。[Source code]
新しいクエリはシンプルな設計に
新しいトークンを作ったり基本的な操作やクエリなどを行うことがとても簡単なのが確認できましたね。でも、ほかに何ができるのでしょうか?ターゲットが選定された、カスタムクエリの操作にラムダを使用するのはどうでしょうか?これは標準のクエリを超えることができます。TokenQueryByクラスを入力しましょう。
ここに基本的なフォーマットがあります。TokenQueryByをインスタンス化し、自分の想像力だけに限定され作成したpredicates(SQLにおける述語)を渡します。それをtoken Selectorに渡します。
TokenQueryBy tokenQueryBy = new TokenQueryBy(
issuer,
it -> {...condition...}
);
Selector selector = new DatabaseTokenSelection(getServiceHub());
return selector.selectTokens(totalAmountHeld, tokenQueryBy);
spaceshipのサンプルでは、このパターンをシンプルでクリエイティブに使用しています。ユーティリティ関数は、すべてのfungible tokensを小数で返します。これは「なめらかな変更ファインダー」です。これを例として使用すると、任意のタイプのpredicatesを作成できます。[Source code]
今後は?
これまで最新のリリースによって変更されたToken SDKのAPIの一部を紹介してきました。まだまだ 、開発の際に躓きやすいポジティブな変更や機能がたくさんあります。
リリース初期段階から、世界中にある大企業がCorda tokenをCorDappに統合しています。今回ご紹介したものはデジタル資産の表現をもっとの効果的に標準化できる方法の1つだと思います。構築と開発をつづけ、将来のリリースに引き続き注目ください。それまでの間、新しい無料のCordaトレーニングプラットフォームをご覧ください。
Corda上のアプリケーション構築をさらに学びたい方はcorda.netのcommunity pageでほかのCorda開発者とつながりましょう。また、sign upしていただければ最新のアップデートのニュースレターをお送りします。
Written by Taira Nakamura
Updated:2020/6/18