-
Notifications
You must be signed in to change notification settings - Fork 6
/
createRedeemTransaction.cpp
155 lines (111 loc) · 7.65 KB
/
createRedeemTransaction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
transaction createAtomicSwapTetherRedeemTransaction(const ec_private& Alice_private,
const ec_public& Bob_pubkey, const ec_private& Bob_private, const uint64_t& tether_amount,
const uint32_t& locktime, const data_chunk& swap_secret,
const transaction& Funding_tx)
{
payment_address Alice_address=Alice_private.to_payment_address();
data_chunk swap_secret_hash=ripemd160_hash_chunk(swap_secret);
transaction redeem_tx;
redeem_tx.set_version(1u);
//входы транзакции(в идеале лучше было бы, еслиб программа сама находила и строила входы, как например с помощью функции getUTXO, суть ее в том, чтобы обраться к серверу(в данном случае libbitcoin серверу) и отправить запрос на получение данных из блокчейна, из которые уже можно бы было получить UTXO для конкретного адреса,но сервер возвращает пустое множество UTXO, для любого адреса. долгое время не смогя разобраться с этой проблемой, было решено пока возложить на пользователя задачу найти и вписать свой UTXO)
//выходы можно самостоятельно посмотреть на сайте
//https://live.blockcypher.com/btc-testnet/tx/62408b1b14ce9eea82b73b543cfb0bdfc4ec118b9d50c07e6c6d75ba3c6a7b59/
//тут необходимо ввести хэш транзакции в которой есть непотраченный выход
std::string PrevTxHash_str;
std::cout<<"\n write your prev UTXO hash in base16, once output from this will input for channel's creation's transaction:\n";
std::cin>>PrevTxHash_str;
hash_digest PrevTxHash;
decode_hash(PrevTxHash, PrevTxHash_str);
//тут нужно ввести индекс непотраченного выхода, индексация начинается с нуля, выходы например на сайте
//https://live.blockcypher.com/btc-testnet/tx/62408b1b14ce9eea82b73b543cfb0bdfc4ec118b9d50c07e6c6d75ba3c6a7b59/
//расположены сверху внизу в порядке увеличения их индекса
uint32_t PrevTxIndex;
std::cout<<"\n write index unspended output of your UTXO, its output will be input:\n";
std::cin>>PrevTxIndex;
//сдача пользователю, то есть открывающая транзакция (opening_tx) имеет 2 выхода - первый, на счет с мультподписью размер отправляеных на него биткоинов равен ширине канала, второй - сдача пользователю, остаток средств которые он хочет вернуть на свой адрес, он наберет их сам, учитывая какую сумму он хочет потратить на fees
std::string OddMoney_btc;
uint64_t OddMoney_satoshi;
std::cout<<"\n write odd money (in BTC), for creating p2pkh output on your address. Dont forgot about transaction's fees:\n";
std::cin>>OddMoney_btc;
decode_base10(OddMoney_satoshi,OddMoney_btc, btc_decimal_places);
output_point UTXO(PrevTxHash, PrevTxIndex);
input input0;
input0.set_previous_output(UTXO);
input0.set_sequence(0xffffffff);
input input1;
output_point FundingTxOutput(Funding_tx.hash(), 0u);
input1.set_previous_output(FundingTxOutput);
input1.set_sequence(0x00000000);
redeem_tx.inputs().push_back(input0); //добавим вход без подписи
redeem_tx.inputs().push_back(input1); //добавим вход без подписи
//выходы
//выход с op_return скриптом
operation::list OmniScript;
OmniScript.push_back(operation(opcode::return_));
data_chunk omni_payload;
omni_payload.push_back(0x6f); //o
omni_payload.push_back(0x6d); //m
omni_payload.push_back(0x6e); //n
omni_payload.push_back(0x69); //i
//version
omni_payload.push_back(0x00); //0
omni_payload.push_back(0x00); //0
//type =0 ("simple send")
omni_payload.push_back(0x00); //0
omni_payload.push_back(0x00); //0
//token identifier =31 (TetherUS)
omni_payload.push_back(0x00); //0
omni_payload.push_back(0x00); //0
omni_payload.push_back(0x00); //0
omni_payload.push_back(0x1f); //1
//amount
for(int i=7; i>=0; i--)
{
omni_payload.push_back( tether_amount>>(8*i));
}
OmniScript.push_back( operation(omni_payload) );
output Output0(0u, OmniScript); //создаем второй выход
//выход на адрес боба
operation::list p2pkhScript0=script::to_pay_key_hash_pattern(Bob_pubkey.to_payment_address().hash()); //скрипт для возвращает сдачу себе
output Output1(SATOSHI_FOR_OMNI_OUTPUT, p2pkhScript0); //создаем второй выход
//выход на адрес алисы
operation::list p2pkhScript1=script::to_pay_key_hash_pattern(Alice_address.hash()); //скрипт для возвращает сдачу себе
output Output2(OddMoney_satoshi, p2pkhScript1); //создаем второй выход
redeem_tx.outputs().push_back(Output0);
redeem_tx.outputs().push_back(Output1);
redeem_tx.outputs().push_back(Output2);
operation::list SwapScript;
SwapScript.push_back( operation(opcode::ripemd160) );
SwapScript.push_back( operation(swap_secret_hash) );
SwapScript.push_back( operation(opcode::equal) );
SwapScript.push_back( operation(opcode::if_) );
SwapScript.push_back( operation(to_chunk(Bob_pubkey.point())) );
SwapScript.push_back( operation(opcode::else_) );
SwapScript.push_back( operation(uint32_to_data_chunk_inverse(locktime)) );
SwapScript.push_back( operation(opcode::checklocktimeverify) );
SwapScript.push_back( operation(opcode::drop) );
SwapScript.push_back( operation(to_chunk(Alice_private.to_public().point() )) );
SwapScript.push_back( operation(opcode::endif) );
SwapScript.push_back( operation(opcode::checksig) );
script redeem_script(SwapScript);
//подпишемся!
endorsement Sig0;
// считаем скрипт выхода соответствующнго входу0 равен p2pkhScript
script::create_endorsement(Sig0, Alice_private.secret(), p2pkhScript1, redeem_tx, 0u, sighash_algorithm::all);
operation::list sig_script0;
sig_script0.push_back(operation(Sig0));
sig_script0.push_back(operation(to_chunk(Alice_private.to_public().point() )));
script InputScript0(sig_script0);
redeem_tx.inputs()[0].set_script(InputScript0);
std::cout<<"REDEEM TRANSACTION WITHOUT BOB'S SIGN:\n"<<encode_base16( redeem_tx.to_data() )<<std::endl;
endorsement Sig1;
// считаем скрипт выхода соответствующнго входу0 равен p2pkhScript
script::create_endorsement(Sig1, Bob_private.secret(), redeem_script , redeem_tx, 1u, sighash_algorithm::all);
operation::list sig_script1;
sig_script1.push_back(operation(Sig1));
sig_script1.push_back(operation( swap_secret ));
sig_script1.push_back( operation(to_chunk(redeem_script.to_data(false)) ));
script InputScript1(sig_script1);
redeem_tx.inputs()[1].set_script(InputScript1);
return redeem_tx;
}