Skip to content

Commit afe26fd

Browse files
committed
Cardano: Add vote delegation to node api
Added vote delegation to node api and wasm generation. Signed-off-by: RostarMarek <[email protected]>
1 parent 5f22d90 commit afe26fd

File tree

8 files changed

+144
-4
lines changed

8 files changed

+144
-4
lines changed

CHANGELOG-npm.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
## 0.8.0
6+
- cardano: allow vote delegation
7+
58
## 0.7.0
69
- btc: handle error when an input's previous transaction is required but missing
710
- btc: add support for regtest

NPM_VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.7.0
1+
0.8.0

sandbox/src/Cardano.tsx

+56-2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,11 @@ function CardanoAddress({ bb02 }: Props) {
133133
<ShowError err={err} />
134134
</form>
135135
</div>
136-
137136
);
138137
}
139138

140139
function CardanoSignTransaction({ bb02 }: Props) {
141-
type TxType = 'normal' | 'zero-ttl' | 'tokens' | 'delegate' | 'withdraw-staking-rewards';
140+
type TxType = 'normal' | 'zero-ttl' | 'tokens' | 'delegate' | 'vote-delegation' | 'vote-delegation-keyhash' | 'withdraw-staking-rewards';
142141
const [txType, setTxType] = useState<TxType>('normal');
143142
const [running, setRunning] = useState(false);
144143
const [result, setResult] = useState<bitbox.CardanoSignTransactionResult | undefined>();
@@ -151,6 +150,8 @@ function CardanoSignTransaction({ bb02 }: Props) {
151150
['zero-ttl', 'Transaction with TTL=0'],
152151
['tokens', 'Transaction sending tokens'],
153152
['delegate', 'Delegate staking to a pool'],
153+
['vote-delegation', 'Delegate vote to a dRep'],
154+
['vote-delegation-keyhash', 'Delegate vote to a dRep with a keyhash'],
154155
['withdraw-staking-rewards', 'Withdraw staking rewards'],
155156
];
156157

@@ -176,6 +177,8 @@ function CardanoSignTransaction({ bb02 }: Props) {
176177
};
177178

178179
const changeAddress = await bb02.cardanoAddress(network, changeConfig, false);
180+
const drepType: bitbox.CardanoDrepType = 'alwaysAbstain';
181+
const drepKeyHashType: bitbox.CardanoDrepType = 'keyHash';
179182
const transaction = () => {
180183
switch (txType) {
181184
case 'normal':
@@ -290,6 +293,57 @@ function CardanoSignTransaction({ bb02 }: Props) {
290293
validityIntervalStart: BigInt(41110811),
291294
allowZeroTTL: false,
292295
};
296+
case 'vote-delegation':
297+
return {
298+
network,
299+
inputs,
300+
outputs: [
301+
{
302+
encodedAddress: changeAddress,
303+
value: BigInt(2741512),
304+
scriptConfig: changeConfig,
305+
},
306+
],
307+
fee: BigInt(191681),
308+
ttl: BigInt(41539125),
309+
certificates: [
310+
{
311+
voteDelegation: {
312+
keypath: "m/1852'/1815'/0'/2/0",
313+
type: drepType,
314+
},
315+
},
316+
],
317+
withdrawals: [],
318+
validityIntervalStart: BigInt(41110811),
319+
allowZeroTTL: false,
320+
};
321+
case 'vote-delegation-keyhash':
322+
return {
323+
network,
324+
inputs,
325+
outputs: [
326+
{
327+
encodedAddress: changeAddress,
328+
value: BigInt(2741512),
329+
scriptConfig: changeConfig,
330+
},
331+
],
332+
fee: BigInt(191681),
333+
ttl: BigInt(41539125),
334+
certificates: [
335+
{
336+
voteDelegation: {
337+
keypath: "m/1852'/1815'/0'/2/0",
338+
type: drepKeyHashType,
339+
drepCredhash: new Uint8Array(hexToArrayBuffer("abababababababababababababababababababababababababababab")),
340+
},
341+
},
342+
],
343+
withdrawals: [],
344+
validityIntervalStart: BigInt(41110811),
345+
allowZeroTTL: false,
346+
};
293347
case 'withdraw-staking-rewards':
294348
return {
295349
network,

scripts/build-protos.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ fn add_serde_attrs(c: &mut prost_build::Config) {
6767
"shiftcrypto.bitbox02.BTCPubRequest.XPubType.CAPITAL_YPUB",
6868
"serde(rename = \"Ypub\")",
6969
),
70+
// Cardano
7071
(
7172
"shiftcrypto.bitbox02.CardanoNetwork.CardanoMainnet",
7273
"serde(rename = \"mainnet\")",
7374
),
74-
// Cardano
7575
(
7676
"shiftcrypto.bitbox02.CardanoNetwork.CardanoTestnet",
7777
"serde(rename = \"testnet\")",
@@ -92,6 +92,10 @@ fn add_serde_attrs(c: &mut prost_build::Config) {
9292
"keypath_stake",
9393
"serde(deserialize_with = \"crate::keypath::serde_deserialize\")",
9494
),
95+
(
96+
"shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegation.type",
97+
"serde(deserialize_with = \"crate::cardano::serde_deserialize_drep_type\")",
98+
),
9599
];
96100

97101
for (path, attr) in type_attrs {

src/cardano.rs

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ where
1515
Ok(network as i32)
1616
}
1717

18+
#[cfg(feature = "wasm")]
19+
pub(crate) fn serde_deserialize_drep_type<'de, D>(deserializer: D) -> Result<i32, D::Error>
20+
where
21+
D: serde::Deserializer<'de>,
22+
{
23+
use serde::Deserialize;
24+
let drep_type = pb::cardano_sign_transaction_request::certificate::vote_delegation::CardanoDRepType::deserialize(deserializer)?;
25+
Ok(drep_type as i32)
26+
}
27+
1828
#[cfg(feature = "wasm")]
1929
#[derive(serde::Deserialize)]
2030
pub(crate) struct SerdeScriptConfig(pb::cardano_script_config::Config);

src/shiftcrypto.bitbox02.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,10 @@ pub mod cardano_sign_transaction_request {
12481248
)]
12491249
pub keypath: ::prost::alloc::vec::Vec<u32>,
12501250
#[prost(enumeration = "vote_delegation::CardanoDRepType", tag = "2")]
1251+
#[cfg_attr(
1252+
feature = "wasm",
1253+
serde(deserialize_with = "crate::cardano::serde_deserialize_drep_type")
1254+
)]
12511255
pub r#type: i32,
12521256
#[prost(bytes = "vec", optional, tag = "3")]
12531257
pub drep_credhash: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,

src/wasm/types.rs

+8
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ type CardanoOutput = {
104104
scriptConfig?: CardanoScriptConfig;
105105
assetGroups?: CardanoAssetGroup[];
106106
}
107+
type CardanoDrepType = 'keyHash' | 'scriptHash' | 'alwaysAbstain' | 'alwaysNoConfidence'
107108
type CardanoCertificate =
108109
| {
109110
stakeRegistration: {
@@ -120,6 +121,13 @@ type CardanoCertificate =
120121
keypath: Keypath
121122
poolKeyhash: Uint8Array
122123
}
124+
}
125+
| {
126+
voteDelegation: {
127+
keypath: Keypath
128+
type: CardanoDrepType
129+
drepCredhash?: Uint8Array
130+
}
123131
};
124132
type CardanoWithdrawal = {
125133
keypath: Keypath;

tests/subtests/test_cardano.rs

+57
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,63 @@ pub async fn test(bitbox: &PairedBitBox) {
223223
);
224224
}
225225
}
226+
// Delegating vote to a drep with a keyhash
227+
{
228+
let transaction = pb::CardanoSignTransactionRequest {
229+
network: pb::CardanoNetwork::CardanoMainnet as i32,
230+
inputs: vec![pb::cardano_sign_transaction_request::Input {
231+
keypath: keypath_input.to_vec(),
232+
prev_out_hash: hex::decode(
233+
"59864ee73ca5d91098a32b3ce9811bac1996dcbaefa6b6247dcaafb5779c2538",
234+
)
235+
.unwrap(),
236+
prev_out_index: 0,
237+
}],
238+
outputs: vec![pb::cardano_sign_transaction_request::Output {
239+
encoded_address: change_address.clone(),
240+
value: 2741512,
241+
script_config: Some(change_config.clone()),
242+
..Default::default()
243+
}],
244+
fee: 191681,
245+
ttl: 41539125,
246+
certificates: vec![
247+
pb::cardano_sign_transaction_request::Certificate {
248+
cert: Some(
249+
pb::cardano_sign_transaction_request::certificate::Cert::VoteDelegation(
250+
pb::cardano_sign_transaction_request::certificate::VoteDelegation {
251+
keypath: vec![2147485500, 2147485463, 2147483648, 2, 0],
252+
r#type: pb::cardano_sign_transaction_request::certificate::vote_delegation::CardanoDRepType::KeyHash.into(),
253+
drep_credhash: Some(hex::decode(
254+
"abababababababababababababababababababababababababababab",
255+
)
256+
.unwrap()),
257+
},
258+
),
259+
),
260+
},
261+
],
262+
withdrawals: vec![],
263+
validity_interval_start: 41110811,
264+
allow_zero_ttl: false,
265+
};
266+
267+
if semver::VersionReq::parse(">=9.21.0")
268+
.unwrap()
269+
.matches(bitbox.version())
270+
{
271+
let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap();
272+
assert_eq!(witness.shelley_witnesses.len(), 2);
273+
assert_eq!(
274+
hex::encode(&witness.shelley_witnesses[0].public_key),
275+
"6b5d4134cfc66281827d51cb0196f1a951ce168c19ba1314233f43d39d91e2bc",
276+
);
277+
assert_eq!(
278+
hex::encode(&witness.shelley_witnesses[1].public_key),
279+
"ed0d6426efcae3b02b963db0997845ba43ed53c131aa2f0faa01976ddcdb3751",
280+
);
281+
}
282+
}
226283
// Withdrawing staking rewards...
227284
{
228285
let transaction = pb::CardanoSignTransactionRequest {

0 commit comments

Comments
 (0)