# Платежные каналы Биткойн
> Данный протокол максимально близко копирует LN(в основном для уменьшения багов в первой версии).
Платежный канал - это последовательность действительных транзакций, которые создаются, подписываются и обмениваются вне цепочки двумя контрагентами. Транзакции не передаются в сеть Биткойн во время работы канала. Только когда одна или обе стороны готовы закрыть канал, происходит трансляция одной ***транзакции закрытия***. Это позволяет многократно обновлять сальдо между двумя сторонами, в результате чего на блокчейне возникают только две транзакции: одна для открытия канала и одна для закрытия канала.
Платежные каналы - это абстракция, которая существуют как последовательность состояний обязательств. Чтобы канал находился в состоянии обязательства:
1. Обе стороны согласовывают свои балансы в канале. Это **свойство согласованности**.
2. Любая из сторон может в одностороннем порядке закрыть канал путем трансляции транзакции, чтобы получить полный баланс. Это **свойство побега**.
3. До тех пор, пока стороны имеют доступ к блокчейну и действуют правильно, ни одина из них не может быть лишена своего полного баланса. Это **свойство охраны**.
Вместе, эти свойства гарантируют, что платежные каналы не требуют доверия между контрагентами и означают, что ни одна из сторон не берет на себя риск, входя в канал.
> ***Это важно.*** Чтобы обновить сальдо в канале, канал проходит через изменение состояния обязательства и переход в новое состояние обязательства с обновленным сальдо. Платежный канал всегда будет находиться в состоянии обязательства или в состоянии перехода между двумя состояниями обязательств. Те это [протокол двухфазной фиксации][1].
## Witness tx's
Для корректного функциониирования каналов необходимо форматировать транзакции согласно [BIP-141][bip_141]. Основная причина этого требования - свойство, описанное как [гибкость транзакций][2]
## Транзакции
> отличная утилита для отладки транзакций, скриптов в них входящих - https://github.com/stevenroose/hal
Биткоин Транзакции - это наборы входов(IN_x) и выходов(OUT_x). В самом простом варианте транзакция состоит из одного входа и одного выхода. IN_1 = OUT_1 - коммисия майнеру.
```json
{
"txid": "3c40fa75014d66801bd141f9e03cef1a4741b48e0d68721590c44a15225c628c",
"hash": "b9a04355aa151d39192d003f2a145afacc2e1b7a1a63a66b5e6a10cf8b91e236",
"size": 345,
"weight": 720,
"vsize": 180,
"version": 2,
"locktime": 0,
"inputs":[],
"outputs":[]
```
где ***inputs*** содержит 1 или более входов:
```json
"inputs":[
{
"prevout": "ac1963f26fff40b247ce593e3d450cb0d5d7fea8b18142dda1475b077d088d6e:0",
"txid": "ac1963f26fff40b247ce593e3d450cb0d5d7fea8b18142dda1475b077d088d6e",
"vout": 0,
"script_sig": {
"hex": "",
"asm": ""
},
"sequence": 4294967294,
"witness": [
"",
"30440220ff49e786aca7296cdf70348d72a1f9a9ae0a3c6a4507258177138017e8b3d38902203affcbc7073fe1d3fef435729f18e8be7e2256046342edf368e02d8c81d65be001",
"304402205855a1186a323305d7e78ba8f239bce84a332f70599bae9242ab68ce7d29bcca022049722109bc325b36b1485d19fd3f20e99897a3e7cddb1e0ce6cb69966a630c7601",
"5221034ab20d8f688c2f6cdf306bf3aa4e62a1d7f8615763e416f4a84d8560348d36832103b6e6be854aaa366e07a2cdc7732b8a10f1c0d62f35fcb7cd4606a44677bf341f52ae"
]
}
]
```
а ***outputs*** один или более выходов:
```json
"outputs": [
{
"value": 300000000,
"script_pub_key": {
"hex": "00141ceb9ccfb2f8941d4599ee15e245b61421204972",
"asm": "OP_0 OP_PUSHBYTES_20 1ceb9ccfb2f8941d4599ee15e245b61421204972",
"type": "p2wpkh",
"address": "bc1qrn4eenajlz2p63veac27y3dkzssjqjtjzx4ret"
}
},
{
"value": 698000000,
"script_pub_key": {
"hex": "002099713c8d95330a6cb2cb0e3c8e2b9c56adf899a55b8cf0dd82b6dd4251cbecb9",
"asm": "OP_0 OP_PUSHBYTES_32 99713c8d95330a6cb2cb0e3c8e2b9c56adf899a55b8cf0dd82b6dd4251cbecb9",
"type": "p2wsh",
"address": "bc1qn9cnerv4xv9xevktpc7gu2uu26kl3xd9twx0phvzkmw5y5wtajust4ree3"
}
}
]
```
Скрипт свидетеля, полная версия которого приведена во входе, а сокращенная в выходе - это интелектуальный замок, авторизирующий создание транзакции в биткоин, работа которого подчиняется программе написанной на bitcoin script.
До создания этой транзакции IN_0 был OUT_0, те неизрасходованным выходом предыдущей транзакции или Unspent Transaction Output(UTXO).
OUT_1 в свою очередь может быть потрачен как на один, так и на несколько IN_x.
В данной транзакции представленны два типа выходов:
* **p2wpkh** - pay to witness public key hash
или оплата при предоставлении ключа, хэш от которого является замком.
* **p2wsh** - pay to witness script hash или оплата при предоставлении скрипта, хэш от которого является замок.
## Относительная блокировка
Ключевым элементом транзакции, позволяющим сущевствовать канлу является замок, позволяющий расходовать вход двумя способами - первый, без задержки по ключа A. Второй, с задержкой по ключю B.
В данном примере применена задержка OP_CHECKSEQUENCEVERIFY в 2 блока после публикации транзакции:
```cpp
OP_IF
[Ключ отзыва]
OP_ELSE
2 OP_CHECKSEQUENCEVERIFY
OP_DROP
[Ключ Алисы]
OP_ENDIF
OP_CHECKSIG
```
Этот замок позволяет создать транзакцию а затем анулировать ее передав контрагенту приватный ключ для формирования ключа отзыва.
## Базовый протокол L2
Описанный протокол использует механизм относительных блокировок и механизм ключей отзыва, он не предпологает транзакции с промежуточным узлом. Помимо этого данный протокол вводит минимальные требование на хранилище пользователя - ему необходимо хранить только индекс транзакций фиксации и ключей отзыва, полученных от контр-агента.
Для открытия канала клиент и биржа вместе подписывают транзакцию финансирования. До ее публикации обе стороны также подписывают первичную транзакцию фиксации состояния канала - этот этап нужен для обеспечения свойства побега.
Процесс изменение сальдо канала осущевствляется согласно протоколу двухфазной фиксации:
> надо поправить/ с алисами и бобами - это старые примеры, актуализирую после реализации/
0. Алиса запрашивает у L2 уникальный адрес, на который необходимо сгенерировать транзакцию фиксации.
1. Алиса формирует и подписывает транзакцию фиксации на свой адрес и адрес биржи, включая в свой выход замок, содержащий публичный ключ отзыва. Передает сформированную транзакцию L2. вместе с ней Алиса передает приватный ключ отзыва от предыдущей транзакции.
При получении L2 подписанной Алисой транзакции и ключа отзыва предыдущей транзакции происходит фиксация сальдо, те состояние канала считается обновленным.
## Биржевой протокол L2
> Протокол второго слоя тесно связан с [Trade API](https://hackmd.io/pxbPKQ4SSLWkcy5xQetxmw?both) и Bank API.
В общем виде распоряжение на выставление заявки в ордер-бук состоит из метаданных самой заявки и подписи к офчейн транзакции, меняющее сальдо канала на сумму заявки.
При выполнении заказа биржа информирует трейдера о его выполнении и подписывает транзакцию фиксации, уменьшающую сальдо биржи в пользу трейдера.
Важным архитектурным ньюансом является выделение процесса получения транзакции и подписи к ней в отдельный сервис, работающий по запросу. Это позволяет снизить нагрузку с на торговое апи, а также реализовывать в будущем нестандартные интерактивные протоколы L2. Текущий протокол предусматривает передачу обновленного адреса и приватного ключа отмены предыдущей транзакции, инициированной трейдером.
При следующей постановке заказа, трейдер формирует подпись к нему, увеличивающей баланс биржи - в теле ответа получает приватный ключ отзыва, сформированный биржей для последней подписанной ей транзакции, увеличивающую баланс трейдера, одновременно уменьшающую баланс биржи.
При выставлении ордера, подписывая транзакцию фиксации - это означает что трейдер передает бирже право израсходовать средства с канала на сумму обозначенную в подписанной транзакции. Тк формат офф-чейн транзакций не отличается от ончейн, трейдер также сам может опубликовать эту транзакцию в блокчейн - в этом случае биржа имеет возможность во время блокировки отозвать эту транзакцию, имея приватный ключ отзыва - этот механизм позваляет соблюдать свойство "охраны" при любом поведении сторон.
При инициации нового распоряжения, для смены состояния канала трейдеру надо передать приватный ключ отмены от прошлого состояния, смену которого инициировал трейдер. Таким образом происходит анулирование прошлого состояния(публикация такой транзакции не выгодна ни одной из сторон).
*уфф вроде все - 4 абзаца сверху были выстраданны*
Если трейдер отправляет серию заявок, он может поступить двумя способами:
1. Сформировать транзакцию фиксации для пополнения тн "торгового баланса", на сумму серии ордеров.
2. Формировать транзакции фиксации к каждому ордеру.(Такая серия несет задержки, сильно превышающие вариант 1)
Процесс формирование транзакции начинается с запроса трейдера уникального адреса биржи выход на который должен присутствовать в транзакции.
После получания адреса,
подписи происходит в момент обращения трейдера за ней. В теле запроса трейдер сообщает бирже
1. публичный ключ, транзакцию на который нужно сформировать;
2. публичный ключ отзыва для формируемой транзакции;
3. приватный ключ отзыва от предыдущей транзакции фиксации.
4. подпись, в которой фиксируется хэш подписываемой транзакции
При недостатке емкости канала, или его отсутствии биржа или трейдер инициирует формирование транзакции ребалансировки и транзакции начальной фиксации.
## Реализация базового протокола L2
Рассматриваемый протокол оперирует 4 типами транзакций:
**1.** Транзакция ребалансировки (**re-funding**) - он-чейн транзакция открытия или изменения емкости канала, содержит два или более входов, и один или более выходов, требующих подписи обоих сторон для расходования средств входа. Частным случаем такой транзакции являются транзакции открытия и закрытия канала.
**2.** Транзакция фиксации(**commitment**) - офф-чейн транзакция изменения состояния канала.
**3.** Транзакция отзыва(**revocation**) - он-чейн транзакция, предотвращающая публикацию не-актуальной транзакции фиксации, приватный ключ отзыва которой был передан опоненту при переходе в новое состояние.
**4.** Транзакция расходования(**spending**) средств после экспирации блокировки в опубликованной транзакции фиксации.
> полный референс тут: https://gitlab.l2a.io/l2a.io/go-bitcoin
>
Транзакция фиксации:
```golang
func bolt_commitment2(fundingTx primitives.Transaction) {
// Пример комитмента от алисы, для боба следует сделать по подобию
alphaPrivateKey, _ := wallet.PrivateKeyFromHex(ALPHA_PRIVATE_KEY)
alphaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(alphaPrivateKey))
betaPrivateKey, _ := wallet.PrivateKeyFromHex(BETA_PRIVATE_KEY)
betaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(betaPrivateKey))
redeemScript := script.CreateMultisigRedeemScript(2, []wallet.CompressedPublicKey{
alphaPublicKey,
betaPublicKey,
})
fmt.Println("FUNDING TX:")
fmt.Println(&fundingTx)
// Tx
var tx primitives.Transaction
tx.Version = 2
//tx.LockTime = 0x20000000
tx.LockTime = 0
tx.Outputs = make([]primitives.Output, 2)
// To Remote
tx.Outputs[0].Value = 0
gammaPrivateKey, _ := wallet.PrivateKeyFromHex(GAMMA_PRIVATE_KEY)
gammaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(gammaPrivateKey))
tx.Outputs[0].ScriptPubKey = script.P2WPKHScriptPupKey(crypto.Hash160(gammaPublicKey[:]))
// To Local
tx.Outputs[1].Value = 999990000
deltaPrivateKey, _ := wallet.PrivateKeyFromHex(DELTA_PRIVATE_KEY)
deltaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(deltaPrivateKey))
epsilonPrivateKey, _ := wallet.PrivateKeyFromHex(EPSILON_PRIVATE_KEY)
epsilonPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(epsilonPrivateKey))
/*
OP_IF
0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19
OP_ELSE
2 OP_CHECKSEQUENCEVERIFY
OP_DROP
03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c
OP_ENDIF
OP_CHECKSIG
*/
buf := new(bytes.Buffer)
buf.WriteByte(script.OP_IF)
buf.WriteByte(script.OP_DATA_33)
buf.Write(deltaPublicKey[:])
buf.WriteByte(script.OP_ELSE)
buf.WriteByte(script.OP_2)
buf.WriteByte(script.OP_CHECKSEQUENCEVERIFY)
buf.WriteByte(script.OP_DROP)
buf.WriteByte(script.OP_DATA_33)
buf.Write(epsilonPublicKey[:])
buf.WriteByte(script.OP_ENDIF)
buf.WriteByte(script.OP_CHECKSIG)
tx.Outputs[1].ScriptPubKey = script.P2WSHScriptPubKey(buf.Bytes())
// Input
tx.Inputs = make([]primitives.Input, 1)
tx.Inputs[0].Outpoint.Hash = fundingTx.TxId()
tx.Inputs[0].Outpoint.Index = 0
tx.Inputs[0].Sequence = 0xfffffffe
alphaSig := signSW(tx, 0, redeemScript, fundingTx.Outputs[0].Value, alphaPrivateKey)
betaSig := signSW(tx, 0, redeemScript, fundingTx.Outputs[0].Value, betaPrivateKey)
tx.Inputs[0].Witnesses = make([][]byte, 4)
tx.Inputs[0].Witnesses[1] = alphaSig
tx.Inputs[0].Witnesses[2] = betaSig
tx.Inputs[0].Witnesses[3] = redeemScript
tx.IsSegwit = true
tx.SegwitFlag = 1
fmt.Println("TX:")
fmt.Println(&tx)
fmt.Println(hex.EncodeToString(tx.Bytes()))
fmt.Println()
}
```
Транзакция ребалансировки:
```golang
func bolt_funding2() {
alphaPrivateKey, _ := wallet.PrivateKeyFromHex(ALPHA_PRIVATE_KEY)
alphaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(alphaPrivateKey))
// Ключи от боба для мультисига
betaPrivateKey, _ := wallet.PrivateKeyFromHex(BETA_PRIVATE_KEY)
betaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(betaPrivateKey))
// Redeem script для мультисига
redeemScript := script.CreateMultisigRedeemScript(2, []wallet.CompressedPublicKey{
alphaPublicKey,
betaPublicKey,
})
// Prev Tx
prevTxRaw, _ := hex.DecodeString("0200000001ce2ebc5717236a64e51aaba16e4582561d3f8330bee92b08ad43ff0056a9d549000000006a4730440220794bcd6aa72d49a3e7b0b1ef3ee3aeaad69e8d3405cb6336a58601e65c9e7d3d02200ef5049305509117a191a6a062a6468335551bd80e8cb8317bdfec4887e7722101210245cbfcc4d64c4c77a8341c6c4eafe13c59f9a4bae1852a3a64d1346c435903dafeffffff02400caa3b000000001976a9142007a791f3c0c9eb4d6bfec931b3442339bbc2f288ac00c0ae1d000000001976a91479b9f70bcf4d43cb58566b2e71f063d6b0fff7a688ace7000000")
prevTx := primitives.NewTransaction(bytes.NewBuffer(prevTxRaw))
fmt.Println("PREV TX:")
fmt.Println(&prevTx)
// Tx
var tx primitives.Transaction
tx.Version = 2
tx.LockTime = 0
tx.Inputs = make([]primitives.Input, 1)
tx.Outputs = make([]primitives.Output, 1)
tx.Inputs[0].Outpoint.Hash = prevTx.TxId()
tx.Inputs[0].Outpoint.Index = 0
tx.Inputs[0].Sequence = 0xffffffff
tx.Outputs[0].Value = 1000000000
tx.Outputs[0].ScriptPubKey = script.P2WSHScriptPubKey(redeemScript)
sig, _ := sign.SignTx(tx, 0, prevTx.Outputs[0].ScriptPubKey, sign.SIGHASH_ALL, alphaPrivateKey)
tx.Inputs[0].ScriptSig = script.P2PHKScriptSig(sig, alphaPublicKey)
fmt.Println("TX:")
fmt.Println(&tx)
fmt.Println(hex.EncodeToString(tx.Bytes()))
fmt.Println()
bolt_commitment2(tx)
}
```
Транзакция Боба, публикуемая в блокчейн, в случае если Алиса опубликовала транзакцию, передав перед этим приватный ключ отзыва Бобу:
```golang
func bolt_commitment_revoke() {
// Боб анулирует комитмент алисы
deltaPrivateKey, _ := wallet.PrivateKeyFromHex(DELTA_PRIVATE_KEY)
deltaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(deltaPrivateKey))
epsilonPrivateKey, _ := wallet.PrivateKeyFromHex(EPSILON_PRIVATE_KEY)
epsilonPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(epsilonPrivateKey))
buf := new(bytes.Buffer)
buf.WriteByte(script.OP_IF)
buf.WriteByte(script.OP_DATA_33)
buf.Write(deltaPublicKey[:])
buf.WriteByte(script.OP_ELSE)
buf.WriteByte(script.OP_2)
buf.WriteByte(script.OP_CHECKSEQUENCEVERIFY)
buf.WriteByte(script.OP_DROP)
buf.WriteByte(script.OP_DATA_33)
buf.Write(epsilonPublicKey[:])
buf.WriteByte(script.OP_ENDIF)
buf.WriteByte(script.OP_CHECKSIG)
redeemScript := buf.Bytes()
//////////////
prevTxRaw, _ := hex.DecodeString("020000000001016e8d087d075b47a1dd4281b1a8fed7d5b00c453d3e59ce47b240ff6ff26319ac0000000000feffffff0200a3e111000000001600141ceb9ccfb2f8941d4599ee15e245b6142120497280a29a290000000022002099713c8d95330a6cb2cb0e3c8e2b9c56adf899a55b8cf0dd82b6dd4251cbecb90400473044022003a44f839f42efc1e7a5dfe21b9f22308043bdf8593a7461fe381d6cd0bbe2cb02206668a29d408e754a6a217f65de2210cf63048336cfe7ec4455598e5a60b01cbc0147304402205321ad257dfe1c7519e9c63299eff46b5959478ae49869cef6a67c44ec62064f02200297e65b63844a126fb4cd9cbc29023d2c3f5126351ea995562a60dd54c47c64014752210229a0cd0024360e55d2c7e82ef87045b45766938510309f493b8597d661329bef21037db83169f00341bcb1db1feb78e1ffe56060f32c5eaf079f64454d7a4e3fd74752ae00000000")
prevTx := primitives.NewTransaction(bytes.NewBuffer(prevTxRaw))
fmt.Println("PREV TX:")
fmt.Println(&prevTx)
toPubKey, _ := wallet.CompressedPublicKeyFromHex("033ac8dfd1fb0afe42247655c7b862e1a7fddfef2d3f3b2c29a5884bd6879ea55a")
// Tx
var tx primitives.Transaction
tx.Version = 2
tx.LockTime = 0
// Output
tx.Outputs = make([]primitives.Output, 1)
tx.Outputs[0].Value = 697000000
tx.Outputs[0].ScriptPubKey = script.P2PHKScriptPupKey(crypto.Hash160(toPubKey[:]))
// Input
tx.Inputs = make([]primitives.Input, 1)
tx.Inputs[0].Outpoint.Hash = prevTx.TxId()
tx.Inputs[0].Outpoint.Index = 1
tx.Inputs[0].Sequence = 0
deltaSig := signSW(tx, 0, redeemScript, prevTx.Outputs[1].Value, deltaPrivateKey)
tx.IsSegwit = true
tx.SegwitFlag = 1
tx.Inputs[0].Witnesses = make([][]byte, 3)
tx.Inputs[0].Witnesses[0] = deltaSig
tx.Inputs[0].Witnesses[1] = []byte{1}
tx.Inputs[0].Witnesses[2] = redeemScript
fmt.Println("TX:")
fmt.Println(&tx)
fmt.Println(hex.EncodeToString(tx.Bytes()))
fmt.Println()
}
```
Транзакция расходования, публикуемая после окончания блокировки:
```golang
func bolt_commitment_delay() {
// Алиса забирает свое бабло после задержки вывода
deltaPrivateKey, _ := wallet.PrivateKeyFromHex(DELTA_PRIVATE_KEY)
deltaPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(deltaPrivateKey))
epsilonPrivateKey, _ := wallet.PrivateKeyFromHex(EPSILON_PRIVATE_KEY)
epsilonPublicKey := wallet.CompressPublicKey(wallet.PublicKeyFromPrivateKey(epsilonPrivateKey))
buf := new(bytes.Buffer)
buf.WriteByte(script.OP_IF)
buf.WriteByte(script.OP_DATA_33)
buf.Write(deltaPublicKey[:])
buf.WriteByte(script.OP_ELSE)
buf.WriteByte(script.OP_2)
buf.WriteByte(script.OP_CHECKSEQUENCEVERIFY)
buf.WriteByte(script.OP_DROP)
buf.WriteByte(script.OP_DATA_33)
buf.Write(epsilonPublicKey[:])
buf.WriteByte(script.OP_ENDIF)
buf.WriteByte(script.OP_CHECKSIG)
redeemScript := buf.Bytes()
fmt.Println(hex.EncodeToString(redeemScript))
//////////////
prevTxRaw, _ := hex.DecodeString("0200000000010181e348787048ff78e2ec1cf6a731e7bcb2c4fa0e11ca93ea1a8296a5b3a58f3c0000000000feffffff0200a3e111000000001600141ceb9ccfb2f8941d4599ee15e245b6142120497280a29a290000000022002099713c8d95330a6cb2cb0e3c8e2b9c56adf899a55b8cf0dd82b6dd4251cbecb9040047304402204f0f4a172e5321bf7543d0b3ae2cb5bb411a583761db81e3b2c9b6a75347e8cb022055563104ab6ac93c78c406d64f3ba3a08d2f9a078863ecebf01fb3e108963f1a014730440220017d823706e611da971919c71833361d3f4059748ad415b52a049d465d365c1e02206cf65ab717a46792c923ca4e035c43f3b4bfdd8211387febbbe8ab5bdd657d49014752210229a0cd0024360e55d2c7e82ef87045b45766938510309f493b8597d661329bef21037db83169f00341bcb1db1feb78e1ffe56060f32c5eaf079f64454d7a4e3fd74752ae00000000")
prevTx := primitives.NewTransaction(bytes.NewBuffer(prevTxRaw))
fmt.Println("PREV TX:")
fmt.Println(&prevTx)
toPubKey, _ := wallet.CompressedPublicKeyFromHex("033ac8dfd1fb0afe42247655c7b862e1a7fddfef2d3f3b2c29a5884bd6879ea55a")
// Tx
var tx primitives.Transaction
tx.Version = 2
tx.LockTime = 0
// Output
tx.Outputs = make([]primitives.Output, 1)
tx.Outputs[0].Value = 697000000
tx.Outputs[0].ScriptPubKey = script.P2PHKScriptPupKey(crypto.Hash160(toPubKey[:]))
// Input
tx.Inputs = make([]primitives.Input, 1)
tx.Inputs[0].Outpoint.Hash = prevTx.TxId()
tx.Inputs[0].Outpoint.Index = 1
tx.Inputs[0].Sequence = 2
epsilonSig := signSW(tx, 0, redeemScript, prevTx.Outputs[1].Value, epsilonPrivateKey)
tx.IsSegwit = true
tx.SegwitFlag = 1
tx.Inputs[0].Witnesses = make([][]byte, 3)
tx.Inputs[0].Witnesses[0] = epsilonSig
//tx.Inputs[0].Witnesses[1] = []byte{1}
tx.Inputs[0].Witnesses[2] = redeemScript
fmt.Println("TX:")
fmt.Println(&tx)
fmt.Println(hex.EncodeToString(tx.Bytes()))
fmt.Println()
// non-mandatory-script-verify-flag (Locktime requirement not satisfied) (code 64) (code -26)
}
```
## Bank API
### Общие сведения
Bank API - это набор функий для управления балансами.
#### Типы балансов
1. **User balance** - баланс пользователя
- **Contracts** - **количество коинов/токенов на адресе пользователя**, с котором ассоциирован его канал
- **UXTO** - количество sat/msat, доступное пользователю в канале, не аллоцрованное офф-чейн транзакцией.
2. **Off-chain balance** - общий баланс канала
- **Contracts** - **количество коинов/токенов на балансе контракта**, отправленное с адреса клиента и прикрепленное к этому адресу
- **UXTO** - видимо, это **емкость канала**.
3. **Withdrawable balance** - баланс канала, доступный для вывода
- **Contracts** - количество коинов/токенов на балансе контракта, **разрешенное контрактом для вывода пользователем**
- **UXTO** - **TBA** // мы к такой опции пока не готовы
4. **Trading balance** - торговый баланс
- **Contracts** - количество коинов/токенов на балансе контракта, **переданное бирже посредством off-chain подписи** *(по сути это значение `-BalanceChange` [c минусом] в контракте, но это **не точно**)*
- **Bitcoin** - сумма, обозначенная в последнем коммите. Не может превышать емкости канала между пользователем и биржей.
При этом в любой момент времени жизни канала справедливо следующее:
```txt
trading + withdrawable = off-chain
```
***??? Справедливо ли это для биткоина?*** / Да.
### Управление балансами
Для управления балансами Bank API сервис предоставляет 4 метода:
1. **Deposit** - пополнение **off-chain** баланса (**`user =>> off-chain`**)
- **Contracts** - внесение пользователем коинов/токенов на **баланс контракта**
- **Bitcoin** - ребалансировка канала со стороны пользователя.`func bolt_funding(2)`
> /deposit
2. **Withdraw** - вывод из **off-chain** баланса (**`user <<= off-chain`**)
- **Contracts** - запрос **контракта** на перевод коинов/токенов с **баланс контракта** на баланса
- **Bitcoin** - ребалансировка канала со стороны пользователя.`func bolt_funding(2)`
3. **Approve** - пополнение **trading** баланса (**`off-chain =>> trading`**)`func bolt_comitment(2)`
- **Contracts** - "разрешение" **бирже** потратить часть текущего доступного **off-chain** баланса биржей посредством предоставления **подписи соответствующей off-chain подписи**
- **Bitcoin** - коммит транзакция трейдер->биржа.
4. **Collect** - вывод из **trading** баланса (**`off-chain <<= trading`**)`func bolt_comitment(2)`
- **Contracts** - запрос **бирже** на предоставление **подписи соответствующей off-chain транзакции**, разблокирующей часть текущего **trading** баланса
- **Bitcoin** - коммит транзакция биржа->трейдер.
#### Технические детали
TBA
## Полезные тестовые данные
### Ethereum
Использованные ключи:
**PrivateKey** `a2fad1164999327c75e09b38a8e56dfb24b5d3f87e8acb130e98bc3ef82f34b8`
**PublicKey** `04b8863c2bf104934f7e81ddb13f25dfcae031c7324f60a519c27d636918d3207f0f4b13d01d07bb8269a426c732f74d19db3e12e3b42ea0e1d4d5087a9def7991`
**Address** `0xeaE4382E0cb2e4DEA6D2EEEdfa2D9378A92e8408`
#### Проверка подписи транзакции в Ethereum (эталон)
```txt
Raw tx:
f88834843b9aca008303d09094d3008f8aa802b12445ad0a03e53956f5e8f66d3e80a498aa0da30000000000000000000000000000000000000000000000000000000000093a80
Signed raw tx for Ethereum Mainnet:
f88834843b9aca008303d09094d3008f8aa802b12445ad0a03e53956f5e8f66d3e80a498aa0da30000000000000000000000000000000000000000000000000000000000093a802ca09aee0850580e2334b6418a60664c8ee7c26ffcb5f2a6e590a71415018a7897dfa0787607a398e9c7db9e66a12c9fc33d20ffec72d28ca4e8a88f377e2d15d24fa5
Signed raw tx for Ethereum Rinkeby Testnet:
f88834843b9aca008303d09094d3008f8aa802b12445ad0a03e53956f5e8f66d3e80a498aa0da30000000000000000000000000000000000000000000000000000000000093a801ca0611b3deb5b53583b9814476e3f9f3a75d25d6f216b6be7b4598b512537b71c8ea029710f4e2b95144444328e67d53bcba1368a97791d32dbf5b953f967cec89300
```
[1]: https://en.wikipedia.org/wiki/Two-phase_commit_protocol
[2]: https://en.bitcoin.it/wiki/Transaction_malleability
[bip_141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki