LoginSignup
3
0

More than 5 years have passed since last update.

NEM2カタパルトで双方向ペイメントチャネルするには その2 トランザクションは作れるのか

Last updated at Posted at 2018-12-29

はじめに

前回の記事

いろいろ書いてあるが、図に載っているトランザクションは本当に作れるのか。

図中にあるトランザクションは、2種類である。両者とも、Aggregate Bondedとなっており、Cosignが必要である。特に、Commitment Transactionは、Secret Lockが含まれるレアな使い方をしている。

今回は、図のようなトランザクションが作れて、送信できて、連署して、承認されることを目標とする。

作ってみる

Opening Transaction

image.png

これは比較的簡単である。アカウントからアカウントへの送金トランザクションを2つ作り、アグリゲートトランザクションにしたものである。

いちおう、Lock Fundsは第三者が署名することにしている。この人をGuarantorとする。

function createOpeningTransaction(multisigPublicAccount, account1, account2, accountG) {
    return new Promise((resolve, reject) => {
        const account1Tx = TransferTransaction.create(
            Deadline.create(),
            multisigPublicAccount.address,
            [XEM.createRelative(5)],
            PlainMessage.create('opening tx 5XEM'),
            NetworkType.MIJIN_TEST,
        );
        const publicAccount2Tx = TransferTransaction.create(
            Deadline.create(),
            multisigPublicAccount.address,
            [XEM.createRelative(5)],
            PlainMessage.create('opening tx 5XEM'),
            NetworkType.MIJIN_TEST,
        );
        const opningTransaction = AggregateTransaction.createBonded(
            Deadline.create(),
            [
                account1Tx.toAggregate(account1.publicAccount),
                publicAccount2Tx.toAggregate(account2.publicAccount),
            ],
            NetworkType.MIJIN_TEST
        );
        const signedTransaction = account1.sign(opningTransaction);
        console.log(signedTransaction.hash);
        const lockFundsTransaction = LockFundsTransaction.create(
            Deadline.create(),
            XEM.createRelative(10),
            UInt64.fromUint(480),
            signedTransaction,
            NetworkType.MIJIN_TEST
        );
        const signedLockFundsTransaction = accountG.sign(lockFundsTransaction);
        console.log(signedLockFundsTransaction.hash);
        const cosignAggregateBondedTransaction = function(transaction, account) {
            const cosignatureTransaction = CosignatureTransaction.create(transaction);
            const signedTransaction = account.signCosignatureTransaction(cosignatureTransaction);
            return signedTransaction;
        };
        const listener = new Listener(ENDPOINT);
        const transactionHttp = new TransactionHttp(ENDPOINT);
        listener.open().then(() => {
            transactionHttp.announce(signedLockFundsTransaction).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.confirmed(accountG.address).pipe(
                filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === signedLockFundsTransaction.hash),
                flatMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
            ).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.aggregateBondedAdded(account2.address).pipe(
                filter((_) => !_.signedByAccount(account2.publicAccount)),
                map(transaction => cosignAggregateBondedTransaction(transaction, account2)),
                flatMap(cosignatureSignedTransaction => transactionHttp.announceAggregateBondedCosignature(cosignatureSignedTransaction))
            ).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.confirmed(account1.address).pipe(
                filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === signedTransaction.hash)
            ).subscribe(
                ignore => {
                    listener.close();
                    resolve();
                },
                err => console.error(err)
            );
        }).catch((error) => {
            console.error(error);
        });
    });
}

Commitment Transaction

image.png

こちらは少しややこしい。

マルチシグアカウントからの送金が2つ。そしてシークレットロックトランザクションが1つ入っている。

function createCommitmentTransaction(multisigPublicAccount, account1, account2, accountG, amount1, amount2, secret) {
    return new Promise((resolve, reject) => {
        const account1Tx = TransferTransaction.create(
            Deadline.create(),
            account1.address,
            [XEM.createRelative(amount1)],
            PlainMessage.create(`commitment tx ${amount1}XEM`),
            NetworkType.MIJIN_TEST,
        );
        const account2Tx = TransferTransaction.create(
            Deadline.create(),
            account2.address,
            [XEM.createRelative(amount2)],
            PlainMessage.create(`commitment tx ${amount2}XEM`),
            NetworkType.MIJIN_TEST,
        );
        const secretLockTx = SecretLockTransaction.create(
            Deadline.create(),
            XEM.createRelative(amount2),
            UInt64.fromUint(1000 * 10),
            HashType.SHA3_512,
            secret,
            account1.address,
            NetworkType.MIJIN_TEST
        );
        const commitmentTransaction = AggregateTransaction.createBonded(
            Deadline.create(),
            [
                account1Tx.toAggregate(multisigPublicAccount),
                account2Tx.toAggregate(multisigPublicAccount),
                secretLockTx.toAggregate(account2.publicAccount),
            ],
            NetworkType.MIJIN_TEST
        );
        const signedTransaction = account1.sign(commitmentTransaction);
        console.log(signedTransaction.hash);
        const lockFundsTransaction = LockFundsTransaction.create(
            Deadline.create(),
            XEM.createRelative(10),
            UInt64.fromUint(480),
            signedTransaction,
            NetworkType.MIJIN_TEST
        );
        const signedLockFundsTransaction = accountG.sign(lockFundsTransaction);
        console.log(signedLockFundsTransaction.hash);
        const cosignAggregateBondedTransaction = function(transaction, account) {
            const cosignatureTransaction = CosignatureTransaction.create(transaction);
            const signedTransaction = account.signCosignatureTransaction(cosignatureTransaction);
            return signedTransaction;
        };
        const listener = new Listener(ENDPOINT);
        const transactionHttp = new TransactionHttp(ENDPOINT);
        listener.open().then(() => {
            transactionHttp.announce(signedLockFundsTransaction).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.confirmed(accountG.address).pipe(
                filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === signedLockFundsTransaction.hash),
                flatMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
            ).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.aggregateBondedAdded(account2.address).pipe(
                filter((_) => !_.signedByAccount(account2.publicAccount)),
                map(transaction => cosignAggregateBondedTransaction(transaction, account2)),
                flatMap(cosignatureSignedTransaction => transactionHttp.announceAggregateBondedCosignature(cosignatureSignedTransaction))
            ).subscribe(
                x => console.log(x),
                err => console.error(err)
            );
            listener.confirmed(account1.address).pipe(
                filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === signedTransaction.hash)
            ).subscribe(
                ignore => {
                    listener.close();
                    resolve();
                },
                err => console.error(err)
            );
        }).catch((error) => {
            console.error(error);
        });
    });
}

送ってみる

送信者が誰とか、設定値がいくらとかは気にせずに、純粋にconfirmされるかどうかを確認する。

カタパルトは、Alpacaバージョンのものを使う。

ソースはこちら

Alice、Bob、マルチシグアカウントの秘密鍵は、実行の度に新しく作成している。そのため、マルチシグアカウントへの変換とXEMの送金を追加している。

Opening Transaction

Gistに保存したもの

Commitment Transaction

Gistに保存したもの

まとめ

作ることができる

関連

NEM2カタパルトで双方向ペイメントチャネルするには その1 概要
https://qiita.com/planethouki/items/c22a21836d913418de82

NEM2カタパルトで双方向ペイメントチャネルするには その2 トランザクションは作れるのか
https://qiita.com/planethouki/items/53415a14b34bebd450fc

NEM2カタパルトで双方向ペイメントチャネルするには その3 ペイロードの送信と罰則
https://qiita.com/planethouki/items/945239fe04d2af1fb203

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0