仮想通貨Stacksに入門する ー 送金体験
Stacksという銘柄
Stacksは、スマートコントラクトと分散型アプリケーション(DApps)をBitcoin(BTC)に導入するために設計されたレイヤー1ブロックチェーンソリューションです。これらのスマートコントラクトは、セキュリティや安定性など、Bitcoinを強力にしている特徴を一切変えることなく、Bitcoinを支えています。
これらのDAppsは、オープンでモジュール化されているため、開発者はお互いのアプリの上に構築することができ、通常のアプリでは不可能な機能を作り出すことができます。StacksはベースレイヤーとしてBitcoinを使用しているため、ネットワーク上で起こるすべてのことは、最も広く使用されていて、最も安全なブロックチェーンーBitcoinで決済されます。
このプラットフォームには、Stacksトークン(STX)が使用されており、トークンはスマートコントラクトの実行、取引の処理、Stacks 2.0ブロックチェーンへの新しいデジタルアセットの登録に使用されています。
このプラットフォームは以前はBlockstackとして知られていましたが、エコシステムとオープンソースプロジェクトをBlockstack PBC(オリジナルプロトコルを構築した会社)から「切り離す」ために、2020年第4四半期にStacksにブランド名を変更しました。
Stacks 2.0のメインネットは、2021年1月にローンチしました。
typescriptで送金体験をする
新しいStacks2.0アカウントを生成する
stacksのcliを使用することで、めっちゃ簡単にアカウントを作成することができます。
# stacksのcliをインストールする
npm install --global @stacks/cli
# 新しいアカウントを作成し、詳細を新しいファイルに保存
# '-t' オプションは、これをテストネットのアカウントとするもの
stx make_keychain -t > cli_keychain.json
cli_keychain.jsonの中身は以下のような感じになっている。新しい秘密鍵ごとに新しいアカウントが自動的に存在する。手動でStacks2.0ブロックチェーンのアカウントをインスタンス化する必要がなくなる。
{
// ニーモニック: アカウントにアクセスするために使用される24語のシード
"mnemonic": "aaa bbb ccc ddd ...",
"keyInfo": {
// keyInfo.privateKey: アカウント秘密鍵で、トークン転送に必要ではsenderKeyと呼ばれることがある
"privateKey": "5a3f1f15245bb3fb...",
// keyInfo.address: アカウントのスタックアドレス
"address": "STJRM2AMVF90ER6G3RW1QTF85E3HZH37006D5ER1",
// keyInfo.btcAddress: 口座に対応するBTCアドレス
"btcAddress": "biwSd6KTEvJcyX2R8oyfgj5REuLzczMYC1",
// keyInfo.wif: btcAddressの秘密鍵を圧縮したもの
"wif": "L4HXn7PLmzoNW...",
// keyInfo.index: 0から始まるアカウントのナンス
"index": 0
}
}
秘密鍵・公開鍵・ウォレットアドレスの生成
import {
makeRandomPrivKey,
privateKeyToString,
getAddressFromPrivateKey,
TransactionVersion,
getPublicKey,
StacksPrivateKey,
StacksPublicKey,
} from "@stacks/transactions";
// 秘密鍵の作成
const privateKey: StacksPrivateKey = makeRandomPrivKey();
// 秘密鍵から公開鍵の作成
const publicKey: StacksPublicKey = getPublicKey(privateKey);
const networkType: TransactionVersion = TransactionVersion.Testnet
// テストネットで秘密鍵からウォレットアドレスを作成
const stacksAddress: string = getAddressFromPrivateKey(
privateKeyToString(privateKey),
networkType // メインネットで作成する場合は、ここは記述しなくて良い
);
console.log(stacksAddress);
プログラムではなく、パッケージでこれらの作成をすることもできる
$ npx -q stacks-gen sk --testnet
ファーセットを受け取る
上記で作成したアドレスに対して、ファーセットを受け取る。ニーモニックを入れてコネクションすれば、以下の画面で受け取ることができる。
この方法もあるが、curlで叩いて受け取ることもできる
curl -L 'https://api.testnet.hiro.so/extended/v1/faucets/stx' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"address": "<自分のウォレットアドレスをここに>",
"stacking": false
}'
トランザクションが成功すると以下のように表示される(このtxIdなどはそれっぽいですが、ただの乱数なので、存在しません。)
{
"success": true,
"txId": "0x9ec281e9550213c79929b8b7d90dc32979d0562766f115f71591969458215d9d",
"txRaw": "80800000000400c2963cf9cf3f60311c34087ce3cb55e51a2f20de92e3ecaf3c4ac277de6471217d23f019daa6234c6009a17ff33442aa9f3e80503020000000000051a1a01e0acdf4d4291b0de9ff9cdb579c895a635f9c7e518f5397d29bd8b3b45c8abdbc413000000000001368c00000000000000b4000033312aa92093bcd8c893b59f434adee97000000001dcd650046617563657400000000000000000000000000000000000000000000000000000000"
}
ウォレットアドレスで検索してみると以下のようになっています。受け取ることができましたね!
残高の確認
curlコマンドで残高を確認する
上記のようにexplorerを使用して確認することもできますが、curlコマンドを叩くことで、残高を確認することもできます。
$ curl 'https://stacks-node-api.testnet.stacks.co/extended/v1/address/<ウォレットアドレス>/balances'
{
"stx": {
"balance": "500000000",
"total_sent": "0",
"total_received": "500000000",
"total_fees_sent": "0",
"total_miner_rewards_received": "0",
"lock_tx_id": "",
"locked": "0",
"lock_height": 0,
"burnchain_lock_height": 0,
"burnchain_unlock_height": 0
},
"fungible_tokens": {},
"non_fungible_tokens": {}
}%
"balance": "500000000",
とあるように、残高が確認できます。
APIを使って残高を確認する
axiosを使用して、以下のようにAPIを叩いて、残高を取得することができます。
import axios from 'axios';
// testnetのAPI(メインネットの場合は、testnetをmainnetにしてください。)
const API_URL = 'https://stacks-node-api.testnet.stacks.co';
const walletAddress = '<自分のウォレットアドレスをここに。>';
// レスポンスがないとエラーになってしまうので、同期処理にする
async function getStacksWalletBalance(address: string): Promise<number> {
try {
const response: AxiosResponse = await axios.get(`${API_URL}/extended/v1/address/${address}/balances`);
const balanceMicrostacks: number = response.data.stx.balance;
// 過分性が6桁なので、補完する
const balanceSTX: number = balanceMicrostacks / 1_000_000;
return balanceSTX;
} catch (error) {
console.error('Error getting wallet balance:', error);
throw error;
}
}
// 残高を表示する
getStacksWalletBalance(walletAddress)
.then(balance => console.log(`ウォレットの残高: ${balance}STX`))
.catch(error => console.error(error));
ウォレットの残高: 500STX
トランザクションの作成とブロードキャスト
Stacksのようなブロックチェーン上でトランザクションを作成し、ブロードキャストするには、通常いくつかのステップが必要となります!
-
トランザクションの作成:
送信者のアドレス、受信者のアドレス、送信金額、スマートコントラクトに必要な追加データ(該当する場合があれば...)など、必要な情報をすべて含むトランザクションオブジェクトを作成する必要があります。 -
トランザクションへの署名:
取引は送信者の秘密鍵で署名されないといけません。このプロセスはトランザクションを保護し、それが本当に送信者によって作成されたものであることを検証します。 -
トランザクションのブロードキャスト:
署名されると、トランザクションはネットワークにブロードキャストされ、そこでマイナーによって次のブロックに含まれるように伝えられます。
実装
import { StacksTestnet } from '@stacks/network';
import {
makeSTXTokenTransfer,
broadcastTransaction,
AnchorMode,
} from '@stacks/transactions';
import { BigNumber } from 'bignumber.js';
const API_URL: string = 'https://stacks-node-api.testnet.stacks.co';
const senderKey: string = '<送信者の秘密鍵をここに。>';
const recipient: string = '<受信者のウォレットアドレスをここに>';
const amountToSend: BigNumber = new BigNumber(1000); // 送金額をここに。ただし、1 STX = 1,000,000 microstacksなので、マイクロスタックの単位で考える。
const network = new StacksTestnet();
async function createAndBroadcastTransaction() {
try {
// 1. トランザクションの作成
const txOptions = {
recipient,
amount: amountToSend.toString(),
senderKey,
network,
anchorMode: AnchorMode.Any,
memo: 'Test transaction',
};
// 2. トランザクションへの署名
// トランザクションは送信者の公開鍵と共に作成された時に自動で署名されるようになっている。
const transaction = await makeSTXTokenTransfer(txOptions);
// 3. トランザクションのブロードキャスト
const broadcastResponse = await broadcastTransaction(transaction, network);
console.log('ブロードキャストトランザクションのレスポンス:', broadcastResponse);
if (broadcastResponse.hasOwnProperty('error')) {
throw new Error(`エラー!!: ${broadcastResponse.error}`);
}
return broadcastResponse;
} catch (error) {
console.error('失敗!!!!:', error);
throw error;
}
}
// Use the function
createAndBroadcastTransaction()
.then(response => console.log('ブロードキャスト成功!!!!:', response))
.catch(error => console.error('エラー!!:', error));
ブロードキャストトランザクションのレスポンス: {
txid: '6f419be2c1d354f6edd5e83a0a945263c9eb4d3217ff559c9f473a9940f3f0ac'
}
ブロードキャスト成功!!!!: {
txid: '6f419be2c1d354f6edd5e83a0a945263c9eb4d3217ff559c9f473a9940f3f0ac'
}
Explorerから確認する
txid: transaction idを検索してみると結果が以下のように出てきます。
ちゃんと送金されていますね!!
残高確認してみる
前述した残高確認で残高を確認してみましょう。
ウォレット残高: 499.984135STX
参考資料
Stacks Explorer by Hiro [Testnet mode]
stacks-archive/stacks-transactions-js: The JavaScript library for generating Stacks 2.0 transactions
Discussion