Skip to content

Commit

Permalink
feat: 🎸 support dao withdraw phrase2 simple transaction builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Liu Chuankai committed May 11, 2023
1 parent 9f38c81 commit 471d566
Show file tree
Hide file tree
Showing 13 changed files with 321 additions and 80 deletions.
2 changes: 1 addition & 1 deletion examples/dao_deposit_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
contexts.add_context(Box::new(context) as Box<_>);

builder.set_change_lock((&sender).into());
let mut tx_with_groups = builder.build(&contexts)?;
let mut tx_with_groups = builder.build(&mut contexts)?;

let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Expand Down
2 changes: 1 addition & 1 deletion examples/dao_withdraw_phrase1_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
contexts.add_context(Box::new(context) as Box<_>);

builder.set_change_lock((&sender).into());
let mut tx_with_groups = builder.build(&contexts)?;
let mut tx_with_groups = builder.build(&mut contexts)?;

let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Expand Down
61 changes: 61 additions & 0 deletions examples/dao_withdraw_phrase2_example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use ckb_sdk::{
transaction::{
builder::{CkbTransactionBuilder, SimpleTransactionBuilder},
handler::{dao, HandlerContexts},
input::InputIterator,
signer::{SignContexts, TransactionSigner},
TransactionBuilderConfiguration,
},
Address, CkbRpcClient, NetworkInfo,
};
use ckb_types::h256;
use std::{error::Error as StdErr, str::FromStr};

fn main() -> Result<(), Box<dyn StdErr>> {
let network_info = NetworkInfo::testnet();
let sender = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r")?;

let configuration = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;

let iterator = InputIterator::new(vec![(&sender).into()], configuration.network_info());
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);

let input_outpoint = serde_json::from_str::<ckb_jsonrpc_types::OutPoint>(
r#"
{
"tx_hash": "0x770f930ed3bf35664cb6a112edce3287712f0613c74c1f1176e099ee51268489",
"index": "0x0"
}
"#,
)
.unwrap();
let context =
dao::WithdrawPhrase2Context::new(vec![input_outpoint.into()], network_info.url.clone());
let mut contexts = HandlerContexts::default();
contexts.add_context(Box::new(context) as Box<_>);

builder.set_change_lock((&sender).into());
let mut tx_with_groups = builder.build(&mut contexts)?;

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

let private_keys = vec![h256!(
"0x6c9ed03816e3111e49384b8d180174ad08e29feb1393ea1b51cef1c505d4e36a"
)];
TransactionSigner::new(&network_info).sign_transaction(
&mut tx_with_groups,
&SignContexts::new_sighash_h256(private_keys)?,
)?;

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

let tx_hash = CkbRpcClient::new(network_info.url.as_str())
.send_transaction(json_tx.inner, None)
.expect("send transaction");
// example tx: 0xaae93c573848a632f06f01c7c444c90aa490253f35b4212d147882266960a267
println!(">>> tx {} sent! <<<", tx_hash);

Ok(())
}
2 changes: 1 addition & 1 deletion examples/send_ckb_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
let addr = Address::from_str(sender)?;
builder.add_output_from_addr(&receiver, Capacity::shannons(510_0000_0000u64));
builder.set_change_addr(&addr);
let mut tx_with_groups = builder.build(&Default::default())?;
let mut tx_with_groups = builder.build(&mut Default::default())?;

let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Expand Down
2 changes: 1 addition & 1 deletion examples/send_ckb_multisig_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
builder.add_output_from_addr(&addr, Capacity::shannons(501_0000_0000u64));
builder.set_change_addr(&sender_addr);
let mut tx_with_groups =
builder.build(&HandlerContexts::new_multisig(multisig_config.clone()))?;
builder.build(&mut HandlerContexts::new_multisig(multisig_config.clone()))?;

let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Expand Down
49 changes: 42 additions & 7 deletions src/core/advanced_builders.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use ckb_types::{constants, core, packed, prelude::*};
use ckb_types::{
constants, core,
packed::{self, WitnessArgs},
prelude::*,
};
use derive_getters::Getters;

/// An advanced builder for [`TransactionView`].
Expand All @@ -20,7 +24,7 @@ pub struct TransactionBuilder {
#[getter(rename = "get_outputs")]
pub outputs: Vec<packed::CellOutput>,
#[getter(rename = "get_witnesses")]
pub witnesses: Vec<packed::Bytes>,
pub witnesses: Vec<WitnessArgs>,
#[getter(rename = "get_outputs_data")]
pub outputs_data: Vec<packed::Bytes>,
}
Expand Down Expand Up @@ -138,11 +142,12 @@ macro_rules! def_dedup_setter_for_vector {
$comment_push:expr, $comment_extend:expr,
) => {
#[doc = $comment_push]
pub fn $func_push(&mut self, v: $prefix::$type) -> &mut Self {
if !self.$field.contains(&v) {
self.$field.push(v);
pub fn $func_push(&mut self, v: $prefix::$type) -> usize {
if let Some(idx) = self.$field.iter().position(|x| x == &v) {
return idx;
}
self
self.$field.push(v);
self.$field.len() - 1
}
#[doc = $comment_extend]
pub fn $func_extend<T>(&mut self, v: T) -> &mut Self
Expand Down Expand Up @@ -207,7 +212,7 @@ impl TransactionBuilder {
def_setter_for_vector!(
set_i,
witnesses,
Bytes,
WitnessArgs,
witness,
witnesses,
set_witnesses,
Expand All @@ -221,6 +226,32 @@ impl TransactionBuilder {
set_outputs_data
);

pub fn set_witness_lock(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
self.witnesses[i] = self.witnesses[i]
.clone()
.as_builder()
.lock(v.pack())
.build();
self
}

pub fn set_witness_input(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
self.witnesses[i] = self.witnesses[i]
.clone()
.as_builder()
.input_type(v.pack())
.build();
self
}

pub fn set_witness_output(&mut self, i: usize, v: Option<bytes::Bytes>) -> &mut Self {
self.witnesses[i] = self.witnesses[i]
.clone()
.as_builder()
.output_type(v.pack())
.build();
self
}
/// Converts into [`TransactionView`](struct.TransactionView.html).
pub fn build(self) -> core::TransactionView {
let Self {
Expand All @@ -240,6 +271,10 @@ impl TransactionBuilder {
.outputs(outputs.pack())
.outputs_data(outputs_data.pack())
.build();
let witnesses = witnesses
.iter()
.map(|t| t.as_bytes().pack())
.collect::<Vec<_>>();
let tx = packed::Transaction::new_builder()
.raw(raw)
.witnesses(witnesses.pack())
Expand Down
12 changes: 9 additions & 3 deletions src/tests/transaction/sighash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ fn test_transfer_from_sighash() {
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
builder.add_output(output.clone(), ckb_types::packed::Bytes::default());
builder.set_change_lock(sender.clone());
let mut tx_with_groups = builder.build(&Default::default()).expect("build failed");
let mut tx_with_groups = builder
.build(&mut Default::default())
.expect("build failed");

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

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

let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());
Expand Down
40 changes: 24 additions & 16 deletions src/transaction/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use fee_calculator::FeeCalculator;
pub trait CkbTransactionBuilder {
fn build(
&mut self,
contexts: &HandlerContexts,
contexts: &mut HandlerContexts,
) -> Result<TransactionWithScriptGroups, TxBuilderError>;
}

Expand All @@ -36,6 +36,12 @@ pub struct SimpleTransactionBuilder {
reward: u64,
}

pub struct PrepareTransactionViewer<'a> {
pub(crate) transaction_inputs: &'a mut Vec<TransactionInput>,
pub(crate) tx: &'a mut TransactionBuilder,
pub(crate) reward: &'a mut u64,
}

impl SimpleTransactionBuilder {
pub fn new(configuration: TransactionBuilderConfiguration, input_iter: InputIterator) -> Self {
Self {
Expand Down Expand Up @@ -137,16 +143,13 @@ impl SimpleTransactionBuilder {
}

fn prepare_transaction(
transaction_inputs: &mut Vec<TransactionInput>,
tx_builder: &mut crate::core::TransactionBuilder,
viewer: &mut PrepareTransactionViewer,
configuration: &TransactionBuilderConfiguration,
contexts: &HandlerContexts,
contexts: &mut HandlerContexts,
) -> Result<(), TxBuilderError> {
for handler in configuration.get_script_handlers() {
for context in &contexts.contexts {
if let Ok(true) =
handler.prepare_transaction(transaction_inputs, tx_builder, context.as_ref())
{
for context in &mut contexts.contexts {
if handler.prepare_transaction(viewer, context.as_mut())? {
break;
}
}
Expand All @@ -162,17 +165,22 @@ macro_rules! celloutput_capacity {
}};
}

macro_rules! prepare_veiwer {
($self:ident) => {
PrepareTransactionViewer {
transaction_inputs: &mut $self.transaction_inputs,
tx: &mut $self.tx,
reward: &mut $self.reward,
}
};
}

impl CkbTransactionBuilder for SimpleTransactionBuilder {
fn build(
&mut self,
contexts: &HandlerContexts,
contexts: &mut HandlerContexts,
) -> Result<TransactionWithScriptGroups, TxBuilderError> {
Self::prepare_transaction(
&mut self.transaction_inputs,
&mut self.tx,
&self.configuration,
contexts,
)?;
Self::prepare_transaction(&mut prepare_veiwer!(self), &self.configuration, contexts)?;
let mut lock_groups: HashMap<Byte32, ScriptGroup> = HashMap::default();
let mut type_groups: HashMap<Byte32, ScriptGroup> = HashMap::default();
let mut outputs_capacity = 0u64;
Expand All @@ -198,7 +206,7 @@ impl CkbTransactionBuilder for SimpleTransactionBuilder {
let input = input?;
self.tx.input(input.cell_input());
let previous_output = input.previous_output();
self.tx.witness(packed::Bytes::default());
self.tx.witness(Default::default());
let lock_script = previous_output.lock();
let script_group = lock_groups
.entry(lock_script.calc_script_hash())
Expand Down
Loading

0 comments on commit 471d566

Please sign in to comment.