Skip to content

Commit fd48654

Browse files
committed
Implement sign tx intent for Trezor signer
1 parent 7e0f2c8 commit fd48654

File tree

8 files changed

+181
-8
lines changed

8 files changed

+181
-8
lines changed

common/src/chain/transaction/signed_transaction_intent.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ pub struct SignedTransactionIntent {
6666
}
6767

6868
impl SignedTransactionIntent {
69+
pub fn new_unchecked(signed_message: String, signatures: Vec<Vec<u8>>) -> Self {
70+
Self {
71+
signed_message,
72+
signatures,
73+
}
74+
}
75+
6976
/// Create a signed intent given the id of the transaction and its input destinations.
7077
///
7178
/// Only PublicKeyHash and PublicKey destinations are supported by this function.

wallet/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,5 @@ tempfile.workspace = true
4545
[features]
4646
trezor = ["dep:trezor-client", "wallet-types/trezor"]
4747
trezor-emulator = []
48+
49+
default = ["trezor"]

wallet/src/signer/software_signer/tests.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,74 @@ fn sign_message(#[case] seed: Seed) {
8383
res.verify_signature(&config, &destination, &message_challenge).unwrap();
8484
}
8585

86+
#[rstest]
87+
#[trace]
88+
#[case(Seed::from_entropy())]
89+
fn sign_transaction_intent(#[case] seed: Seed) {
90+
use common::primitives::Idable;
91+
92+
let mut rng = make_seedable_rng(seed);
93+
94+
let config = Arc::new(create_regtest());
95+
let db = Arc::new(Store::new(DefaultBackend::new_in_memory()).unwrap());
96+
let mut db_tx = db.transaction_rw_unlocked(None).unwrap();
97+
98+
let master_key_chain = MasterKeyChain::new_from_mnemonic(
99+
config.clone(),
100+
&mut db_tx,
101+
MNEMONIC,
102+
None,
103+
StoreSeedPhrase::DoNotStore,
104+
)
105+
.unwrap();
106+
107+
let key_chain = master_key_chain
108+
.create_account_key_chain(&mut db_tx, DEFAULT_ACCOUNT_INDEX, LOOKAHEAD_SIZE)
109+
.unwrap();
110+
let mut account = Account::new(config.clone(), &mut db_tx, key_chain, None).unwrap();
111+
112+
let mut signer = SoftwareSigner::new(config.clone(), DEFAULT_ACCOUNT_INDEX);
113+
114+
let inputs: Vec<TxInput> = (0..rng.gen_range(1..5))
115+
.map(|_| {
116+
let source_id = if rng.gen_bool(0.5) {
117+
Id::<Transaction>::new(H256::random_using(&mut rng)).into()
118+
} else {
119+
Id::<GenBlock>::new(H256::random_using(&mut rng)).into()
120+
};
121+
TxInput::from_utxo(source_id, rng.next_u32())
122+
})
123+
.collect();
124+
let input_destinations: Vec<_> = (0..inputs.len())
125+
.map(|_| account.get_new_address(&mut db_tx, ReceiveFunds).unwrap().1.into_object())
126+
.collect();
127+
128+
let tx = Transaction::new(
129+
0,
130+
inputs,
131+
vec![TxOutput::Transfer(
132+
OutputValue::Coin(Amount::from_atoms(rng.gen())),
133+
account.get_new_address(&mut db_tx, Change).unwrap().1.into_object(),
134+
)],
135+
)
136+
.unwrap();
137+
138+
let intent: String = [rng.gen::<char>(), rng.gen::<char>(), rng.gen::<char>()].iter().collect();
139+
let res = signer
140+
.sign_transaction_intent(
141+
&tx,
142+
&input_destinations,
143+
&intent,
144+
account.key_chain(),
145+
&db_tx,
146+
)
147+
.unwrap();
148+
149+
let expected_signed_message =
150+
SignedTransactionIntent::get_message_to_sign(&intent, &tx.get_id());
151+
res.verify(&config, &input_destinations, &expected_signed_message).unwrap();
152+
}
153+
86154
#[rstest]
87155
#[trace]
88156
#[case(Seed::from_entropy())]

wallet/src/signer/trezor_signer/mod.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use common::{
4444
AccountCommand, AccountSpending, ChainConfig, Destination, OutPointSourceId,
4545
SignedTransactionIntent, Transaction, TxInput, TxOutput,
4646
},
47-
primitives::H256,
47+
primitives::{Idable, H256},
4848
};
4949
use crypto::key::{
5050
extended::ExtendedPublicKey,
@@ -478,13 +478,25 @@ impl Signer for TrezorSigner {
478478

479479
fn sign_transaction_intent(
480480
&mut self,
481-
_transaction: &Transaction,
482-
_input_destinations: &[Destination],
483-
_intent: &str,
484-
_key_chain: &impl AccountKeyChains,
485-
_db_tx: &impl WalletStorageReadUnlocked,
481+
transaction: &Transaction,
482+
input_destinations: &[Destination],
483+
intent: &str,
484+
key_chain: &impl AccountKeyChains,
485+
db_tx: &impl WalletStorageReadUnlocked,
486486
) -> SignerResult<SignedTransactionIntent> {
487-
unimplemented!("FIXME")
487+
let tx_id = transaction.get_id();
488+
let message_to_sign = SignedTransactionIntent::get_message_to_sign(intent, &tx_id);
489+
490+
let mut signatures = Vec::with_capacity(input_destinations.len());
491+
for dest in input_destinations {
492+
let sig = self.sign_challenge(message_to_sign.as_bytes(), dest, key_chain, db_tx)?;
493+
signatures.push(sig.into_raw());
494+
}
495+
496+
Ok(SignedTransactionIntent::new_unchecked(
497+
message_to_sign,
498+
signatures,
499+
))
488500
}
489501
}
490502

wallet/src/signer/trezor_signer/tests.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,78 @@ fn sign_message(#[case] seed: Seed) {
8484
res.verify_signature(&chain_config, &destination, &message_challenge).unwrap();
8585
}
8686

87+
#[rstest]
88+
#[trace]
89+
#[case(Seed::from_entropy())]
90+
fn sign_transaction_intent(#[case] seed: Seed) {
91+
use common::primitives::Idable;
92+
93+
let mut rng = make_seedable_rng(seed);
94+
95+
let config = Arc::new(create_regtest());
96+
let db = Arc::new(Store::new(DefaultBackend::new_in_memory()).unwrap());
97+
let mut db_tx = db.transaction_rw_unlocked(None).unwrap();
98+
99+
let master_key_chain = MasterKeyChain::new_from_mnemonic(
100+
config.clone(),
101+
&mut db_tx,
102+
MNEMONIC,
103+
None,
104+
StoreSeedPhrase::DoNotStore,
105+
)
106+
.unwrap();
107+
108+
let key_chain = master_key_chain
109+
.create_account_key_chain(&mut db_tx, DEFAULT_ACCOUNT_INDEX, LOOKAHEAD_SIZE)
110+
.unwrap();
111+
let mut account = Account::new(config.clone(), &mut db_tx, key_chain, None).unwrap();
112+
113+
let mut devices = find_devices(false);
114+
assert!(!devices.is_empty());
115+
let client = devices.pop().unwrap().connect().unwrap();
116+
117+
let mut signer = TrezorSigner::new(config.clone(), Arc::new(Mutex::new(client)));
118+
119+
let inputs: Vec<TxInput> = (0..rng.gen_range(1..5))
120+
.map(|_| {
121+
let source_id = if rng.gen_bool(0.5) {
122+
Id::<Transaction>::new(H256::random_using(&mut rng)).into()
123+
} else {
124+
Id::<GenBlock>::new(H256::random_using(&mut rng)).into()
125+
};
126+
TxInput::from_utxo(source_id, rng.next_u32())
127+
})
128+
.collect();
129+
let input_destinations: Vec<_> = (0..inputs.len())
130+
.map(|_| account.get_new_address(&mut db_tx, ReceiveFunds).unwrap().1.into_object())
131+
.collect();
132+
133+
let tx = Transaction::new(
134+
0,
135+
inputs,
136+
vec![TxOutput::Transfer(
137+
OutputValue::Coin(Amount::from_atoms(rng.gen())),
138+
account.get_new_address(&mut db_tx, Change).unwrap().1.into_object(),
139+
)],
140+
)
141+
.unwrap();
142+
143+
let intent: String = [rng.gen::<char>(), rng.gen::<char>(), rng.gen::<char>()].iter().collect();
144+
let res = signer
145+
.sign_transaction_intent(
146+
&tx,
147+
&input_destinations,
148+
&intent,
149+
account.key_chain(),
150+
&db_tx,
151+
)
152+
.unwrap();
153+
154+
let expected_signed_message =
155+
SignedTransactionIntent::get_message_to_sign(&intent, &tx.get_id());
156+
res.verify(&config, &input_destinations, &expected_signed_message).unwrap();
157+
}
158+
87159
#[rstest]
88160
#[trace]
89161
#[case(Seed::from_entropy())]

wallet/src/wallet/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,7 @@ where
14521452
intent: String,
14531453
current_fee_rate: FeeRate,
14541454
consolidate_fee_rate: FeeRate,
1455+
additional_utxo_infos: &BTreeMap<PoolOrTokenId, UtxoAdditionalInfo>,
14551456
) -> WalletResult<(SignedTransaction, SignedTransactionIntent)> {
14561457
let (signed_tx, input_destinations) = self.create_transaction_to_addresses_impl(
14571458
account_index,
@@ -1461,7 +1462,7 @@ where
14611462
current_fee_rate,
14621463
consolidate_fee_rate,
14631464
|send_request| send_request.destinations().to_owned(),
1464-
&BTreeMap::new(), // FIXME
1465+
additional_utxo_infos,
14651466
)?;
14661467

14671468
let signed_intent = self.for_account_rw_unlocked(

wallet/wallet-controller/src/runtime_wallet.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,7 @@ impl<B: storage::Backend + 'static> RuntimeWallet<B> {
12131213
intent: String,
12141214
current_fee_rate: FeeRate,
12151215
consolidate_fee_rate: FeeRate,
1216+
additional_utxo_infos: &BTreeMap<PoolOrTokenId, UtxoAdditionalInfo>,
12161217
) -> WalletResult<(SignedTransaction, SignedTransactionIntent)> {
12171218
match self {
12181219
RuntimeWallet::Software(w) => w.create_transaction_to_addresses_with_intent(
@@ -1223,6 +1224,7 @@ impl<B: storage::Backend + 'static> RuntimeWallet<B> {
12231224
intent,
12241225
current_fee_rate,
12251226
consolidate_fee_rate,
1227+
additional_utxo_infos,
12261228
),
12271229
#[cfg(feature = "trezor")]
12281230
RuntimeWallet::Trezor(w) => w.create_transaction_to_addresses_with_intent(
@@ -1233,6 +1235,7 @@ impl<B: storage::Backend + 'static> RuntimeWallet<B> {
12331235
intent,
12341236
current_fee_rate,
12351237
consolidate_fee_rate,
1238+
additional_utxo_infos,
12361239
),
12371240
}
12381241
}

wallet/wallet-controller/src/synced_controller.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,13 @@ where
998998
account_index: U31,
999999
token_info: &UnconfirmedTokenInfo| {
10001000
token_info.check_can_be_used()?;
1001+
let additional_info = BTreeMap::from_iter([(
1002+
PoolOrTokenId::TokenId(token_info.token_id()),
1003+
UtxoAdditionalInfo::TokenInfo(TokenAdditionalInfo {
1004+
num_decimals: token_info.num_decimals(),
1005+
ticker: token_info.token_ticker().to_vec(),
1006+
}),
1007+
)]);
10011008
wallet.create_transaction_to_addresses_with_intent(
10021009
account_index,
10031010
[output],
@@ -1006,6 +1013,7 @@ where
10061013
intent,
10071014
current_fee_rate,
10081015
consolidate_fee_rate,
1016+
&additional_info,
10091017
)
10101018
},
10111019
)

0 commit comments

Comments
 (0)