Skip to content

Instantly share code, notes, and snippets.

@daoka
Last active May 29, 2022 10:02
Show Gist options
  • Save daoka/aef3c428427676ab6fe03327c151dc01 to your computer and use it in GitHub Desktop.
Save daoka/aef3c428427676ab6fe03327c151dc01 to your computer and use it in GitHub Desktop.
Symbol SDK v3 Sandbox
const { SymbolFacade } = require('symbol-sdk').facade;
const { PrivateKey } = require('symbol-sdk/src/CryptoTypes');
const { KeyPair } = require('symbol-sdk/src/symbol/KeyPair');
const { Signature } = require('symbol-sdk/src/symbol/models');
const axios = require('axios').default;
const wsl = require('ws');
async function main() {
const facade = new SymbolFacade('testnet');
// トランザクションをアナウンスするアカウントのキーペアを生成
const alicePrivateKey = new PrivateKey('A************************************************C')
const aliceKeyPair = new KeyPair(alicePrivateKey);
const bobPubicKeyStr = '2******************************************************7';
// トランザクションの有効期限を設定(6時間)
const now = Date.now();
const eadj = 1637848847;
const deadline = BigInt(now - eadj*1000 + 60*60*6*1000);
// 埋め込みトランザクションの作成
const embeddedTx1 = facade.transactionFactory.createEmbedded({
type: 'transfer_transaction',
signerPublicKey: aliceKeyPair.publicKey.toString(),
recipientAddress: 'TD******************************RY',
mosaics: [
{ mosaicId: 0x6BC3BF0D16883E5Fn, amount: 1n }
]
});
const embeddedTx2 = facade.transactionFactory.createEmbedded({
type: 'transfer_transaction',
signerPublicKey: bobPubicKeyStr,
recipientAddress: 'TC******************************GQ',
mosaics: [
{ mosaicId: 0x3A8416DB2D53B6C8n, amount: 1000000n }
]
});
// アグリゲートトランザクションの生成
const embeddedTransactions = [embeddedTx1, embeddedTx2];
const merkleHash = facade.constructor.hashEmbeddedTransactions(embeddedTransactions);
console.log(merkleHash.toString());
const aggregateTx = facade.transactionFactory.create({
type: 'aggregate_bonded_transaction',
signerPublicKey: aliceKeyPair.publicKey.toString(),
deadline: deadline,
transactionsHash: merkleHash,
transactions: embeddedTransactions,
});
// アグリゲートトランザクションの手数料の設定
// 後から署名が追加されるので、それを考慮して手数料計算をする
const feeMultiPlier = 100;
const signerNum = 2
console.log(aggregateTx.size);
aggregateTx.fee.value = BigInt((aggregateTx.size + Signature.SIZE * signerNum) * feeMultiPlier );
// アグリゲートトランザクションの署名
const aggregateTxSignature = facade.signTransaction(aliceKeyPair, aggregateTx);
aggregateTx.signature = new Signature(aggregateTxSignature.bytes);
aggregateTx.network.generationHashSeed = facade.network;
const aggregateTxHash = facade.hashTransaction(aggregateTx);
console.log(aggregateTxHash.toString());
// アグリゲートトランザクションのペイロードを生成
const aggregatePayload = facade.transactionFactory.constructor.attachSignature(aggregateTx, aggregateTxSignature);
//console.log(aggregatePayload);
// ハッシュロックトランザクションの生成
const hashLockTx = facade.transactionFactory.create({
type: 'hash_lock_transaction',
signerPublicKey: aliceKeyPair.publicKey.toString(),
deadline: deadline,
hash: aggregateTxHash,
mosaic: { mosaicId: 0x3A8416DB2D53B6C8n, amount: 10000000n },
duration: BigInt(2*2*60*24)
});
// ハッシュロックトランザクションの手数料を設定
hashLockTx.fee.value = BigInt(hashLockTx.size * feeMultiPlier);
// ハッシュロックトランザクションの署名
const hashLockTxSignature = facade.signTransaction(aliceKeyPair, hashLockTx);
hashLockTx.signature = new Signature(hashLockTxSignature.bytes);
hashLockTx.network.generationHashSeed = facade.network;
const hashLockTxHash = facade.hashTransaction(hashLockTx);
console.log(hashLockTxHash.toString());
// ハッシュロックトランザクションのペイロードを生成
const hashLockPayload = facade.transactionFactory.constructor.attachSignature(hashLockTx, hashLockTxSignature);
const targetAddress = facade.network.publicKeyToAddress(aliceKeyPair.publicKey);
// トランザクションアナウンス後の状態監視のためのリスナーを生成
const ws = new wsl.WebSocket('wss://sym-test.opening-line.jp:3001/ws');
ws.on('open', () => {
console.log('connetion opened');
})
ws.on('close', () => {
console.log('connection closed');
})
ws.on('message', (msg) => {
const res = JSON.parse(msg);
if ('uid' in res) {
console.log(`uid : ${res.uid}`);
// ターゲットアドレスのトランザクションが承認されるの監視
const confirmedBody = `{"uid": "${res.uid}", "subscribe": "confirmedAdded/${targetAddress}"}`
ws.send(confirmedBody);
// ターゲットアドレスの部分トランザクションが追加されるのを監視
const partialBody = `{"uid": "${res.uid}", "subscribe": "partialAdded/${targetAddress}"}`
ws.send(partialBody);
// ターゲットアドレスのトランザクションがエラーになったのを監視
const statusBody = `{"uid": "${res.uid}", "subscribe": "status/${targetAddress}"}`
ws.send(statusBody);
}
// トランザクションが承認されたときに発火
if (res.topic === `confirmedAdded/${targetAddress}` &&
res.data.meta.hash === hashLockTxHash.toString()
) {
// ハッシュロックトランザクションが承認されてから、`PUT /transactions/partial`で
// aggregate bounded transactionをアナウンスする
console.log('hashlock transaction confirmed');
const rest = axios({
headers: {
'Content-Type': 'application/json'
},
method: 'put',
url: 'http://sym-test.opening-line.jp:3000/transactions/partial',
data: aggregatePayload,
}).then((r) => console.log(r.data)).catch((err) => console.log(err));
}
// 部分トランザクションがキャッシュに追加されたときに発火
if (res.topic === `partialAdded/${targetAddress}` &&
res.data.meta.hash === aggregateTxHash.toString()) {
console.log('partial transaction added');
console.log(res);
ws.close();
}
// トランザクションがエラーになったときに発火
if (res.topic === `status/${targetAddress}`) {
console.log(res.data.code);
ws.close();
}
else {
console.log(res);
}
});
// hashlock transactionをアナウンスする
try {
const res = await axios({
headers: {
'Content-Type': 'application/json'
},
method: 'put',
url: 'http://sym-test.opening-line.jp:3000/transactions',
data: hashLockPayload,
});
console.log(res.data);
} catch(err) {
console.error(err);
}
}
main().then();
const { SymbolFacade } = require('symbol-sdk').facade;
const { PrivateKey } = require('symbol-sdk/src/CryptoTypes');
const { KeyPair } = require('symbol-sdk/src/symbol/KeyPair');
const { Signature } = require('symbol-sdk/src/symbol/models');
const axios = require('axios').default;
const wsl = require('ws');
async function main() {
// トランザクションをアナウンスするアカウントのキーペアを生成
const privateKey = new PrivateKey('*********************************************************')
const keyPair = new KeyPair(privateKey);
// トランザクションの有効期限を設定(6時間)
const now = Date.now();
const eadj = 1637848847;
const deadline = BigInt(now - eadj*1000 + 60*60*6*1000);
// 転送トランザクションのインスタンスを生成
const facade = new SymbolFacade('testnet');
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction',
signerPublicKey: keyPair.publicKey.toString(),
deadline: deadline,
recipientAddress: 'TB******************************Y',
mosaics: [
{ mosaicId: 0x3A8416DB2D53B6C8n, amount: 1000000n }
]
});
// 手数料率を設定
const feeMultiPlier = 100;
transaction.fee.value = BigInt(transaction.size * feeMultiPlier);
// トランザクションを署名
const signature = facade.signTransaction(keyPair, transaction);
// トランザクションのハッシュ値を算出
transaction.signature = new Signature(signature.bytes);
transaction.network.generationHashSeed = facade.network
const hash = facade.hashTransaction(transaction);
console.log(hash.toString());
// REST APIにアナウンスする用のペイロードを生成
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const targetAddress = facade.network.publicKeyToAddress(keyPair.publicKey);
console.log(targetAddress.toString());
// トランザクションアナウンス後の状態監視のためのリスナーを生成
const ws = new wsl.WebSocket('wss://sym-test.opening-line.jp:3001/ws');
ws.on('open', () => {
console.log('connetion opened');
})
ws.on('close', () => {
console.log('connection closed');
})
ws.on('message', (msg) => {
const res = JSON.parse(msg);
if ('uid' in res) {
console.log(`uid : ${res.uid}`);
// ターゲットアドレスのトランザクションが承認されるの監視
const confirmedBody = `{"uid": "${res.uid}", "subscribe": "confirmedAdded/${targetAddress}"}`
ws.send(confirmedBody);
// ターゲットアドレスのトランザクションがエラーになったのを監視
const statusBody = `{"uid": "${res.uid}", "subscribe": "status/${targetAddress}"}`
ws.send(statusBody);
}
// トランザクションが承認されたときに発火
if (res.topic === `confirmedAdded/${targetAddress}` &&
res.data.meta.hash === hash.toString()
) {
console.log('transaction confirmed');
ws.close();
}
// トランザクションがエラーになったときに発火
if (res.topic === `status/${targetAddress}` &&
res.data.hash === hash.toString()
) {
console.log(res.data.code);
ws.close();
}
else {
console.log(res);
}
});
// トランザクションをアナウンスする
try {
const res = await axios({
headers: {
'Content-Type': 'application/json'
},
method: 'put',
url: 'http://sym-test.opening-line.jp:3000/transactions',
data: jsonPayload,
});
console.log(res.data);
} catch(err) {
console.error(err);
}
}
main().then();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment