Skip to content

Commit dae479a

Browse files
author
Liu Chuankai
committed
feat: 🎸 support dao withdraw phrase2 simple transaction builder
1 parent 4c24fca commit dae479a

13 files changed

+321
-80
lines changed

‎examples/dao_deposit_example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
2626
contexts.add_context(Box::new(context) as Box<_>);
2727

2828
builder.set_change_lock((&sender).into());
29-
let mut tx_with_groups = builder.build(&contexts)?;
29+
let mut tx_with_groups = builder.build(&mut contexts)?;
3030

3131
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
3232
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());

‎examples/dao_withdraw_phrase1_example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
3535
contexts.add_context(Box::new(context) as Box<_>);
3636

3737
builder.set_change_lock((&sender).into());
38-
let mut tx_with_groups = builder.build(&contexts)?;
38+
let mut tx_with_groups = builder.build(&mut contexts)?;
3939

4040
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
4141
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use ckb_sdk::{
2+
transaction::{
3+
builder::{CkbTransactionBuilder, SimpleTransactionBuilder},
4+
handler::{dao, HandlerContexts},
5+
input::InputIterator,
6+
signer::{SignContexts, TransactionSigner},
7+
TransactionBuilderConfiguration,
8+
},
9+
Address, CkbRpcClient, NetworkInfo,
10+
};
11+
use ckb_types::h256;
12+
use std::{error::Error as StdErr, str::FromStr};
13+
14+
fn main() -> Result<(), Box<dyn StdErr>> {
15+
let network_info = NetworkInfo::testnet();
16+
let sender = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r")?;
17+
18+
let configuration = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
19+
20+
let iterator = InputIterator::new(vec![(&sender).into()], configuration.network_info());
21+
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
22+
23+
let input_outpoint = serde_json::from_str::<ckb_jsonrpc_types::OutPoint>(
24+
r#"
25+
{
26+
"tx_hash": "0x770f930ed3bf35664cb6a112edce3287712f0613c74c1f1176e099ee51268489",
27+
"index": "0x0"
28+
}
29+
"#,
30+
)
31+
.unwrap();
32+
let context =
33+
dao::WithdrawPhrase2Context::new(vec![input_outpoint.into()], network_info.url.clone());
34+
let mut contexts = HandlerContexts::default();
35+
contexts.add_context(Box::new(context) as Box<_>);
36+
37+
builder.set_change_lock((&sender).into());
38+
let mut tx_with_groups = builder.build(&mut contexts)?;
39+
40+
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
41+
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
42+
43+
let private_keys = vec![h256!(
44+
"0x6c9ed03816e3111e49384b8d180174ad08e29feb1393ea1b51cef1c505d4e36a"
45+
)];
46+
TransactionSigner::new(&network_info).sign_transaction(
47+
&mut tx_with_groups,
48+
&SignContexts::new_sighash_h256(private_keys)?,
49+
)?;
50+
51+
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
52+
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
53+
54+
let tx_hash = CkbRpcClient::new(network_info.url.as_str())
55+
.send_transaction(json_tx.inner, None)
56+
.expect("send transaction");
57+
// example tx: 0xaae93c573848a632f06f01c7c444c90aa490253f35b4212d147882266960a267
58+
println!(">>> tx {} sent! <<<", tx_hash);
59+
60+
Ok(())
61+
}

‎examples/send_ckb_example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
2828
let addr = Address::from_str(sender)?;
2929
builder.add_output_from_addr(&receiver, Capacity::shannons(510_0000_0000u64));
3030
builder.set_change_addr(&addr);
31-
let mut tx_with_groups = builder.build(&Default::default())?;
31+
let mut tx_with_groups = builder.build(&mut Default::default())?;
3232

3333
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
3434
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());

‎examples/send_ckb_multisig_example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
4040
builder.add_output_from_addr(&addr, Capacity::shannons(501_0000_0000u64));
4141
builder.set_change_addr(&sender_addr);
4242
let mut tx_with_groups =
43-
builder.build(&HandlerContexts::new_multisig(multisig_config.clone()))?;
43+
builder.build(&mut HandlerContexts::new_multisig(multisig_config.clone()))?;
4444

4545
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
4646
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());

‎src/core/advanced_builders.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use ckb_types::{constants, core, packed, prelude::*};
1+
use ckb_types::{
2+
constants, core,
3+
packed::{self, WitnessArgs},
4+
prelude::*,
5+
};
26
use derive_getters::Getters;
37

48
/// An advanced builder for [`TransactionView`].
@@ -20,7 +24,7 @@ pub struct TransactionBuilder {
2024
#[getter(rename = "get_outputs")]
2125
pub outputs: Vec<packed::CellOutput>,
2226
#[getter(rename = "get_witnesses")]
23-
pub witnesses: Vec<packed::Bytes>,
27+
pub witnesses: Vec<WitnessArgs>,
2428
#[getter(rename = "get_outputs_data")]
2529
pub outputs_data: Vec<packed::Bytes>,
2630
}
@@ -138,11 +142,12 @@ macro_rules! def_dedup_setter_for_vector {
138142
$comment_push:expr, $comment_extend:expr,
139143
) => {
140144
#[doc = $comment_push]
141-
pub fn $func_push(&mut self, v: $prefix::$type) -> &mut Self {
142-
if !self.$field.contains(&v) {
143-
self.$field.push(v);
145+
pub fn $func_push(&mut self, v: $prefix::$type) -> usize {
146+
if let Some(idx) = self.$field.iter().position(|x| x == &v) {
147+
return idx;
144148
}
145-
self
149+
self.$field.push(v);
150+
self.$field.len() - 1
146151
}
147152
#[doc = $comment_extend]
148153
pub fn $func_extend<T>(&mut self, v: T) -> &mut Self
@@ -207,7 +212,7 @@ impl TransactionBuilder {
207212
def_setter_for_vector!(
208213
set_i,
209214
witnesses,
210-
Bytes,
215+
WitnessArgs,
211216
witness,
212217
witnesses,
213218
set_witnesses,
@@ -221,6 +226,32 @@ impl TransactionBuilder {
221226
set_outputs_data
222227
);
223228

229+
pub fn set_witness_lock(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
230+
self.witnesses[i] = self.witnesses[i]
231+
.clone()
232+
.as_builder()
233+
.lock(v.pack())
234+
.build();
235+
self
236+
}
237+
238+
pub fn set_witness_input(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
239+
self.witnesses[i] = self.witnesses[i]
240+
.clone()
241+
.as_builder()
242+
.input_type(v.pack())
243+
.build();
244+
self
245+
}
246+
247+
pub fn set_witness_output(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
248+
self.witnesses[i] = self.witnesses[i]
249+
.clone()
250+
.as_builder()
251+
.output_type(v.pack())
252+
.build();
253+
self
254+
}
224255
/// Converts into [`TransactionView`](struct.TransactionView.html).
225256
pub fn build(self) -> core::TransactionView {
226257
let Self {
@@ -240,6 +271,10 @@ impl TransactionBuilder {
240271
.outputs(outputs.pack())
241272
.outputs_data(outputs_data.pack())
242273
.build();
274+
let witnesses = witnesses
275+
.iter()
276+
.map(|t| t.as_bytes().pack())
277+
.collect::<Vec<_>>();
243278
let tx = packed::Transaction::new_builder()
244279
.raw(raw)
245280
.witnesses(witnesses.pack())

‎src/tests/transaction/sighash.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ fn test_transfer_from_sighash() {
4343
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
4444
builder.add_output(output.clone(), ckb_types::packed::Bytes::default());
4545
builder.set_change_lock(sender.clone());
46-
let mut tx_with_groups = builder.build(&Default::default()).expect("build failed");
46+
let mut tx_with_groups = builder
47+
.build(&mut Default::default())
48+
.expect("build failed");
4749

4850
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
4951
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
@@ -106,7 +108,9 @@ fn test_transfer_from_sighash_samll_to_fee() {
106108
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
107109
builder.add_output(output.clone(), ckb_types::packed::Bytes::default());
108110
builder.set_change_lock(sender.clone());
109-
let mut tx_with_groups = builder.build(&Default::default()).expect("build failed");
111+
let mut tx_with_groups = builder
112+
.build(&mut Default::default())
113+
.expect("build failed");
110114

111115
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
112116
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
@@ -167,7 +171,9 @@ fn test_transfer_from_sighash_samll_to_receiver() {
167171
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
168172
builder.add_output(output, ckb_types::packed::Bytes::default());
169173
builder.set_change_lock(sender.clone());
170-
let mut tx_with_groups = builder.build(&Default::default()).expect("build failed");
174+
let mut tx_with_groups = builder
175+
.build(&mut Default::default())
176+
.expect("build failed");
171177

172178
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
173179
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());

‎src/transaction/builder/mod.rs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub use fee_calculator::FeeCalculator;
2222
pub trait CkbTransactionBuilder {
2323
fn build(
2424
&mut self,
25-
contexts: &HandlerContexts,
25+
contexts: &mut HandlerContexts,
2626
) -> Result<TransactionWithScriptGroups, TxBuilderError>;
2727
}
2828

@@ -36,6 +36,12 @@ pub struct SimpleTransactionBuilder {
3636
reward: u64,
3737
}
3838

39+
pub struct PrepareTransactionViewer<'a> {
40+
pub(crate) transaction_inputs: &'a mut Vec<TransactionInput>,
41+
pub(crate) tx: &'a mut TransactionBuilder,
42+
pub(crate) reward: &'a mut u64,
43+
}
44+
3945
impl SimpleTransactionBuilder {
4046
pub fn new(configuration: TransactionBuilderConfiguration, input_iter: InputIterator) -> Self {
4147
Self {
@@ -137,16 +143,13 @@ impl SimpleTransactionBuilder {
137143
}
138144

139145
fn prepare_transaction(
140-
transaction_inputs: &mut Vec<TransactionInput>,
141-
tx_builder: &mut crate::core::TransactionBuilder,
146+
viewer: &mut PrepareTransactionViewer,
142147
configuration: &TransactionBuilderConfiguration,
143-
contexts: &HandlerContexts,
148+
contexts: &mut HandlerContexts,
144149
) -> Result<(), TxBuilderError> {
145150
for handler in configuration.get_script_handlers() {
146-
for context in &contexts.contexts {
147-
if let Ok(true) =
148-
handler.prepare_transaction(transaction_inputs, tx_builder, context.as_ref())
149-
{
151+
for context in &mut contexts.contexts {
152+
if handler.prepare_transaction(viewer, context.as_mut())? {
150153
break;
151154
}
152155
}
@@ -162,17 +165,22 @@ macro_rules! celloutput_capacity {
162165
}};
163166
}
164167

168+
macro_rules! prepare_veiwer {
169+
($self:ident) => {
170+
PrepareTransactionViewer {
171+
transaction_inputs: &mut $self.transaction_inputs,
172+
tx: &mut $self.tx,
173+
reward: &mut $self.reward,
174+
}
175+
};
176+
}
177+
165178
impl CkbTransactionBuilder for SimpleTransactionBuilder {
166179
fn build(
167180
&mut self,
168-
contexts: &HandlerContexts,
181+
contexts: &mut HandlerContexts,
169182
) -> Result<TransactionWithScriptGroups, TxBuilderError> {
170-
Self::prepare_transaction(
171-
&mut self.transaction_inputs,
172-
&mut self.tx,
173-
&self.configuration,
174-
contexts,
175-
)?;
183+
Self::prepare_transaction(&mut prepare_veiwer!(self), &self.configuration, contexts)?;
176184
let mut lock_groups: HashMap<Byte32, ScriptGroup> = HashMap::default();
177185
let mut type_groups: HashMap<Byte32, ScriptGroup> = HashMap::default();
178186
let mut outputs_capacity = 0u64;
@@ -198,7 +206,7 @@ impl CkbTransactionBuilder for SimpleTransactionBuilder {
198206
let input = input?;
199207
self.tx.input(input.cell_input());
200208
let previous_output = input.previous_output();
201-
self.tx.witness(packed::Bytes::default());
209+
self.tx.witness(Default::default());
202210
let lock_script = previous_output.lock();
203211
let script_group = lock_groups
204212
.entry(lock_script.calc_script_hash())

0 commit comments

Comments
 (0)