Skip to content

Commit

Permalink
Cardano: Add vote delegation to node api
Browse files Browse the repository at this point in the history
Added vote delegation to node api and wasm generation.

Signed-off-by: RostarMarek <[email protected]>
  • Loading branch information
RostarMarek committed Nov 18, 2024
1 parent 5f22d90 commit afe26fd
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG-npm.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

## 0.8.0
- cardano: allow vote delegation

## 0.7.0
- btc: handle error when an input's previous transaction is required but missing
- btc: add support for regtest
Expand Down
2 changes: 1 addition & 1 deletion NPM_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.0
0.8.0
58 changes: 56 additions & 2 deletions sandbox/src/Cardano.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,11 @@ function CardanoAddress({ bb02 }: Props) {
<ShowError err={err} />
</form>
</div>

);
}

function CardanoSignTransaction({ bb02 }: Props) {
type TxType = 'normal' | 'zero-ttl' | 'tokens' | 'delegate' | 'withdraw-staking-rewards';
type TxType = 'normal' | 'zero-ttl' | 'tokens' | 'delegate' | 'vote-delegation' | 'vote-delegation-keyhash' | 'withdraw-staking-rewards';
const [txType, setTxType] = useState<TxType>('normal');
const [running, setRunning] = useState(false);
const [result, setResult] = useState<bitbox.CardanoSignTransactionResult | undefined>();
Expand All @@ -151,6 +150,8 @@ function CardanoSignTransaction({ bb02 }: Props) {
['zero-ttl', 'Transaction with TTL=0'],
['tokens', 'Transaction sending tokens'],
['delegate', 'Delegate staking to a pool'],
['vote-delegation', 'Delegate vote to a dRep'],
['vote-delegation-keyhash', 'Delegate vote to a dRep with a keyhash'],
['withdraw-staking-rewards', 'Withdraw staking rewards'],
];

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

const changeAddress = await bb02.cardanoAddress(network, changeConfig, false);
const drepType: bitbox.CardanoDrepType = 'alwaysAbstain';
const drepKeyHashType: bitbox.CardanoDrepType = 'keyHash';
const transaction = () => {
switch (txType) {
case 'normal':
Expand Down Expand Up @@ -290,6 +293,57 @@ function CardanoSignTransaction({ bb02 }: Props) {
validityIntervalStart: BigInt(41110811),
allowZeroTTL: false,
};
case 'vote-delegation':
return {
network,
inputs,
outputs: [
{
encodedAddress: changeAddress,
value: BigInt(2741512),
scriptConfig: changeConfig,
},
],
fee: BigInt(191681),
ttl: BigInt(41539125),
certificates: [
{
voteDelegation: {
keypath: "m/1852'/1815'/0'/2/0",
type: drepType,
},
},
],
withdrawals: [],
validityIntervalStart: BigInt(41110811),
allowZeroTTL: false,
};
case 'vote-delegation-keyhash':
return {
network,
inputs,
outputs: [
{
encodedAddress: changeAddress,
value: BigInt(2741512),
scriptConfig: changeConfig,
},
],
fee: BigInt(191681),
ttl: BigInt(41539125),
certificates: [
{
voteDelegation: {
keypath: "m/1852'/1815'/0'/2/0",
type: drepKeyHashType,
drepCredhash: new Uint8Array(hexToArrayBuffer("abababababababababababababababababababababababababababab")),
},
},
],
withdrawals: [],
validityIntervalStart: BigInt(41110811),
allowZeroTTL: false,
};
case 'withdraw-staking-rewards':
return {
network,
Expand Down
6 changes: 5 additions & 1 deletion scripts/build-protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ fn add_serde_attrs(c: &mut prost_build::Config) {
"shiftcrypto.bitbox02.BTCPubRequest.XPubType.CAPITAL_YPUB",
"serde(rename = \"Ypub\")",
),
// Cardano
(
"shiftcrypto.bitbox02.CardanoNetwork.CardanoMainnet",
"serde(rename = \"mainnet\")",
),
// Cardano
(
"shiftcrypto.bitbox02.CardanoNetwork.CardanoTestnet",
"serde(rename = \"testnet\")",
Expand All @@ -92,6 +92,10 @@ fn add_serde_attrs(c: &mut prost_build::Config) {
"keypath_stake",
"serde(deserialize_with = \"crate::keypath::serde_deserialize\")",
),
(
"shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegation.type",
"serde(deserialize_with = \"crate::cardano::serde_deserialize_drep_type\")",
),
];

for (path, attr) in type_attrs {
Expand Down
10 changes: 10 additions & 0 deletions src/cardano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ where
Ok(network as i32)
}

#[cfg(feature = "wasm")]
pub(crate) fn serde_deserialize_drep_type<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
let drep_type = pb::cardano_sign_transaction_request::certificate::vote_delegation::CardanoDRepType::deserialize(deserializer)?;
Ok(drep_type as i32)
}

#[cfg(feature = "wasm")]
#[derive(serde::Deserialize)]
pub(crate) struct SerdeScriptConfig(pb::cardano_script_config::Config);
Expand Down
4 changes: 4 additions & 0 deletions src/shiftcrypto.bitbox02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,10 @@ pub mod cardano_sign_transaction_request {
)]
pub keypath: ::prost::alloc::vec::Vec<u32>,
#[prost(enumeration = "vote_delegation::CardanoDRepType", tag = "2")]
#[cfg_attr(
feature = "wasm",
serde(deserialize_with = "crate::cardano::serde_deserialize_drep_type")
)]
pub r#type: i32,
#[prost(bytes = "vec", optional, tag = "3")]
pub drep_credhash: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
Expand Down
8 changes: 8 additions & 0 deletions src/wasm/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ type CardanoOutput = {
scriptConfig?: CardanoScriptConfig;
assetGroups?: CardanoAssetGroup[];
}
type CardanoDrepType = 'keyHash' | 'scriptHash' | 'alwaysAbstain' | 'alwaysNoConfidence'
type CardanoCertificate =
| {
stakeRegistration: {
Expand All @@ -120,6 +121,13 @@ type CardanoCertificate =
keypath: Keypath
poolKeyhash: Uint8Array
}
}
| {
voteDelegation: {
keypath: Keypath
type: CardanoDrepType
drepCredhash?: Uint8Array
}
};
type CardanoWithdrawal = {
keypath: Keypath;
Expand Down
57 changes: 57 additions & 0 deletions tests/subtests/test_cardano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,63 @@ pub async fn test(bitbox: &PairedBitBox) {
);
}
}
// Delegating vote to a drep with a keyhash
{
let transaction = pb::CardanoSignTransactionRequest {
network: pb::CardanoNetwork::CardanoMainnet as i32,
inputs: vec![pb::cardano_sign_transaction_request::Input {
keypath: keypath_input.to_vec(),
prev_out_hash: hex::decode(
"59864ee73ca5d91098a32b3ce9811bac1996dcbaefa6b6247dcaafb5779c2538",
)
.unwrap(),
prev_out_index: 0,
}],
outputs: vec![pb::cardano_sign_transaction_request::Output {
encoded_address: change_address.clone(),
value: 2741512,
script_config: Some(change_config.clone()),
..Default::default()
}],
fee: 191681,
ttl: 41539125,
certificates: vec![
pb::cardano_sign_transaction_request::Certificate {
cert: Some(
pb::cardano_sign_transaction_request::certificate::Cert::VoteDelegation(
pb::cardano_sign_transaction_request::certificate::VoteDelegation {
keypath: vec![2147485500, 2147485463, 2147483648, 2, 0],
r#type: pb::cardano_sign_transaction_request::certificate::vote_delegation::CardanoDRepType::KeyHash.into(),
drep_credhash: Some(hex::decode(
"abababababababababababababababababababababababababababab",
)
.unwrap()),
},
),
),
},
],
withdrawals: vec![],
validity_interval_start: 41110811,
allow_zero_ttl: false,
};

if semver::VersionReq::parse(">=9.21.0")
.unwrap()
.matches(bitbox.version())
{
let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap();
assert_eq!(witness.shelley_witnesses.len(), 2);
assert_eq!(
hex::encode(&witness.shelley_witnesses[0].public_key),
"6b5d4134cfc66281827d51cb0196f1a951ce168c19ba1314233f43d39d91e2bc",
);
assert_eq!(
hex::encode(&witness.shelley_witnesses[1].public_key),
"ed0d6426efcae3b02b963db0997845ba43ed53c131aa2f0faa01976ddcdb3751",
);
}
}
// Withdrawing staking rewards...
{
let transaction = pb::CardanoSignTransactionRequest {
Expand Down

0 comments on commit afe26fd

Please sign in to comment.