Skip to content

Commit

Permalink
fixup! feat(hardware-ledger): sign new certificate types
Browse files Browse the repository at this point in the history
  • Loading branch information
vetalcore committed Apr 17, 2024
1 parent 5bae9c7 commit 3e09025
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 114 deletions.
2 changes: 1 addition & 1 deletion packages/e2e/package.json
Expand Up @@ -78,7 +78,7 @@
"access": "public"
},
"dependencies": {
"@cardano-foundation/ledgerjs-hw-app-cardano": "^6.0.0",
"@cardano-foundation/ledgerjs-hw-app-cardano": "^7.0.0",
"@cardano-ogmios/client": "5.6.0",
"@cardano-sdk/cardano-services": "workspace:~",
"@cardano-sdk/cardano-services-client": "workspace:~",
Expand Down
10 changes: 5 additions & 5 deletions packages/hardware-ledger/src/LedgerKeyAgent.ts
Expand Up @@ -21,11 +21,11 @@ import TransportNodeHid from '@ledgerhq/hw-transport-node-hid-noevents';
import _LedgerConnection, {
Certificate,
CertificateType,
CredentialParams,
CredentialParamsType,
GetVersionResponse,
PoolKeyType,
PoolOwnerType,
StakeCredentialParams,
StakeCredentialParamsType,
Transaction,
TransactionSigningMode,
TxOutputDestinationType
Expand Down Expand Up @@ -127,20 +127,20 @@ const parseEstablishDeviceConnectionSecondParam = (
};

interface StakeCredentialCertificateParams {
stakeCredential: StakeCredentialParams;
stakeCredential: CredentialParams;
}

const containsOnlyScriptHashCreds = (tx: Transaction): boolean => {
const withdrawalsAllScriptHash = !tx.withdrawals?.some(
(withdrawal) => withdrawal.stakeCredential.type !== StakeCredentialParamsType.SCRIPT_HASH
(withdrawal) => withdrawal.stakeCredential.type !== CredentialParamsType.SCRIPT_HASH
);

if (tx.certificates) {
for (const cert of tx.certificates) {
if (!stakeCredentialCert(cert)) return false;

const certParams = cert.params as unknown as StakeCredentialCertificateParams;
if (certParams.stakeCredential.type !== StakeCredentialParamsType.SCRIPT_HASH) return false;
if (certParams.stakeCredential.type !== CredentialParamsType.SCRIPT_HASH) return false;
}
}

Expand Down
201 changes: 109 additions & 92 deletions packages/hardware-ledger/src/transformers/certificates.ts
Expand Up @@ -2,9 +2,9 @@
import * as Crypto from '@cardano-sdk/crypto';
import * as Ledger from '@cardano-foundation/ledgerjs-hw-app-cardano';
import { Cardano } from '@cardano-sdk/core';
import { GroupedAddress, util } from '@cardano-sdk/key-management';
import { InvalidArgumentError, Transform } from '@cardano-sdk/util';
import { LedgerTxTransformerContext } from '../types';
import { util } from '@cardano-sdk/key-management';

const mapAnchorToParams = (certificate: Cardano.Certificate) => ({
...('anchor' in certificate &&
Expand Down Expand Up @@ -43,65 +43,106 @@ const credentialMapper = (
return credentialParams;
};

const stakeCredentialMapper = (
credential: Cardano.Credential,
context: LedgerTxTransformerContext
): Ledger.CredentialParams => {
const knownAddress = context?.knownAddresses.find(
const drepParamsMapper = (
drep: Cardano.Credential,
credentialType: Cardano.CredentialType | Ledger.CredentialParamsType.SCRIPT_HASH,
path: Crypto.BIP32Path | null
): Ledger.KeyPathDRepParams | Ledger.KeyHashDRepParams | Ledger.ScriptHashDRepParams => {
let dRepParams: Ledger.DRepParams;

switch (credentialType) {
case Cardano.CredentialType.KeyHash: {
dRepParams = path
? {
keyPath: path,
type: Ledger.DRepParamsType.KEY_PATH
}
: {
keyHashHex: drep.hash,
type: Ledger.DRepParamsType.KEY_HASH
};
break;
}
case Cardano.CredentialType.ScriptHash:
default: {
dRepParams = {
scriptHashHex: drep.hash,
type: Ledger.DRepParamsType.SCRIPT_HASH
};
}
}

return dRepParams;
};

const getKnownAddress = (credential: Cardano.Credential, context: LedgerTxTransformerContext) =>
context?.knownAddresses.find(
(address) =>
Cardano.RewardAccount.toHash(address.rewardAccount) === (credential.hash as unknown as Crypto.Ed25519KeyHashHex)
);

const getCredentialType = (knownAddress: GroupedAddress | undefined) => {
const rewardAddress = knownAddress ? Cardano.Address.fromBech32(knownAddress.rewardAccount)?.asReward() : null;
return rewardAddress ? rewardAddress.getPaymentCredential().type : Ledger.CredentialParamsType.SCRIPT_HASH;
};

const stakeCredentialMapper = (credential: Cardano.Credential, context: LedgerTxTransformerContext) => {
const knownAddress = getKnownAddress(credential, context);
const credentialType = getCredentialType(knownAddress);
const path = util.stakeKeyPathFromGroupedAddress(knownAddress);
const credentialType = rewardAddress
? rewardAddress.getPaymentCredential().type
: Ledger.CredentialParamsType.SCRIPT_HASH;

return credentialMapper(credential, credentialType, path);
};

const getStakeAddressCertificate = (
certificate: Cardano.StakeAddressCertificate,
context: LedgerTxTransformerContext,
type: Ledger.CertificateType.STAKE_REGISTRATION | Ledger.CertificateType.STAKE_DEREGISTRATION
): Ledger.Certificate => ({
const getStakeAddressCertificate: Transform<
Cardano.StakeAddressCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => ({
params: {
stakeCredential: stakeCredentialMapper(certificate.stakeCredential, context)
stakeCredential: stakeCredentialMapper(certificate.stakeCredential, context!)
},
type
type:
certificate.__typename === Cardano.CertificateType.StakeRegistration
? Ledger.CertificateType.STAKE_REGISTRATION
: Ledger.CertificateType.STAKE_DEREGISTRATION
});

const getNewStakeAddressCertificate = (
certificate: Cardano.NewStakeAddressCertificate,
context: LedgerTxTransformerContext,
type: Ledger.CertificateType.STAKE_REGISTRATION_CONWAY | Ledger.CertificateType.STAKE_DEREGISTRATION_CONWAY
): Ledger.Certificate => ({
const getNewStakeAddressCertificate: Transform<
Cardano.NewStakeAddressCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => ({
params: {
deposit: certificate.deposit,
stakeCredential: stakeCredentialMapper(certificate.stakeCredential, context)
stakeCredential: stakeCredentialMapper(certificate.stakeCredential, context!)
},
type
type:
certificate.__typename === Cardano.CertificateType.Registration
? Ledger.CertificateType.STAKE_REGISTRATION_CONWAY
: Ledger.CertificateType.STAKE_DEREGISTRATION_CONWAY
});

const getAuthorizeCommitteeHotCertificate = (
certificate: Cardano.AuthorizeCommitteeHotCertificate,
context: LedgerTxTransformerContext
): Ledger.Certificate => ({
const getAuthorizeCommitteeHotCertificate: Transform<
Cardano.AuthorizeCommitteeHotCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => ({
params: {
coldCredential: stakeCredentialMapper(certificate.coldCredential, context),
hotCredential: stakeCredentialMapper(certificate.hotCredential, context)
coldCredential: stakeCredentialMapper(certificate.coldCredential, context!),
hotCredential: stakeCredentialMapper(certificate.hotCredential, context!)
},
type: Ledger.CertificateType.AUTHORIZE_COMMITTEE_HOT
});

const getResignCommitteeColdCertificate = (
certificate: Cardano.ResignCommitteeColdCertificate,
context: LedgerTxTransformerContext
): Ledger.Certificate => ({
const getResignCommitteeColdCertificate: Transform<
Cardano.ResignCommitteeColdCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => ({
params: {
...mapAnchorToParams(certificate),
coldCredential: stakeCredentialMapper(certificate.coldCredential, context)
coldCredential: stakeCredentialMapper(certificate.coldCredential, context!)
},
type: Ledger.CertificateType.RESIGN_COMMITTEE_COLD
});
Expand Down Expand Up @@ -257,14 +298,11 @@ const checkDrepPublicKeyAgainstCredential = (
}
};

const drepRegistrationCertificate = (
certificate: Cardano.RegisterDelegateRepresentativeCertificate | Cardano.UnRegisterDelegateRepresentativeCertificate,
context: LedgerTxTransformerContext,
type: Extract<
Ledger.CertificateType,
Ledger.CertificateType.DREP_REGISTRATION | Ledger.CertificateType.DREP_DEREGISTRATION
>
): Ledger.Certificate => {
const drepRegistrationCertificate: Transform<
Cardano.RegisterDelegateRepresentativeCertificate | Cardano.UnRegisterDelegateRepresentativeCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => {
checkDrepPublicKeyAgainstCredential(context?.dRepPublicKey, certificate.dRepCredential.hash);

const params: Ledger.DRepRegistrationParams = {
Expand All @@ -275,43 +313,14 @@ const drepRegistrationCertificate = (

return {
params,
type
type:
certificate.__typename === Cardano.CertificateType.RegisterDelegateRepresentative
? Ledger.CertificateType.DREP_REGISTRATION
: Ledger.CertificateType.DREP_DEREGISTRATION
};
};

const drepParamsMapper = (
drep: Cardano.Credential,
path: Crypto.BIP32Path | null
): Ledger.KeyPathDRepParams | Ledger.KeyHashDRepParams | Ledger.ScriptHashDRepParams => {
let dRepParams: Ledger.DRepParams;

switch (drep.type) {
case Cardano.CredentialType.KeyHash: {
dRepParams = path
? {
keyPath: path,
type: Ledger.DRepParamsType.KEY_PATH
}
: {
keyHashHex: drep.hash,
type: Ledger.DRepParamsType.KEY_HASH
};
break;
}
case Cardano.CredentialType.ScriptHash:
default: {
dRepParams = {
scriptHashHex: drep.hash,
type: Ledger.DRepParamsType.SCRIPT_HASH
};
}
}

return dRepParams;
};

// TODO: do we need to do the same as in stakeCredentialMapper?
const drepMapper = (drep: Cardano.DelegateRepresentative): Ledger.DRepParams => {
const drepMapper = (drep: Cardano.DelegateRepresentative, context: LedgerTxTransformerContext): Ledger.DRepParams => {
if (Cardano.isDRepAlwaysAbstain(drep)) {
return {
type: Ledger.DRepParamsType.ABSTAIN
Expand All @@ -321,18 +330,33 @@ const drepMapper = (drep: Cardano.DelegateRepresentative): Ledger.DRepParams =>
type: Ledger.DRepParamsType.NO_CONFIDENCE
};
} else if (Cardano.isDRepCredential(drep)) {
// TODO: review
return drepParamsMapper(drep, null);
return drepParamsMapper(
drep,
drep.type,
util.accountKeyDerivationPathToBip32Path(context.accountIndex, util.DREP_KEY_DERIVATION_PATH)
);
}
throw new Error('incorrect drep supplied');
};

export const voteDelegationCertificate: Transform<
Cardano.VoteDelegationCertificate,
Ledger.Certificate,
LedgerTxTransformerContext
> = (certificate, context): Ledger.Certificate => ({
params: {
dRep: drepMapper(certificate.dRep, context!),
stakeCredential: stakeCredentialMapper(certificate.stakeCredential, context!)
},
type: Ledger.CertificateType.VOTE_DELEGATION
});

const toCert = (cert: Cardano.Certificate, context: LedgerTxTransformerContext): Ledger.Certificate => {
switch (cert.__typename) {
case Cardano.CertificateType.StakeRegistration:
return getStakeAddressCertificate(cert, context, Ledger.CertificateType.STAKE_REGISTRATION);
return getStakeAddressCertificate(cert, context);
case Cardano.CertificateType.StakeDeregistration:
return getStakeAddressCertificate(cert, context, Ledger.CertificateType.STAKE_DEREGISTRATION);
return getStakeAddressCertificate(cert, context);
case Cardano.CertificateType.StakeDelegation:
return stakeDelegationCertificate(cert, context);
case Cardano.CertificateType.PoolRegistration:
Expand All @@ -342,26 +366,19 @@ const toCert = (cert: Cardano.Certificate, context: LedgerTxTransformerContext):

// Conway Era Certs
case Cardano.CertificateType.Registration:
return getNewStakeAddressCertificate(cert, context, Ledger.CertificateType.STAKE_DEREGISTRATION_CONWAY);
return getNewStakeAddressCertificate(cert, context);
case Cardano.CertificateType.Unregistration:
return getNewStakeAddressCertificate(cert, context, Ledger.CertificateType.STAKE_DEREGISTRATION_CONWAY);
return getNewStakeAddressCertificate(cert, context);
case Cardano.CertificateType.VoteDelegation:
return {
params: {
// TODO: review
dRep: drepMapper(cert.dRep),
stakeCredential: stakeCredentialMapper(cert.stakeCredential, context)
},
type: Ledger.CertificateType.VOTE_DELEGATION
};
return voteDelegationCertificate(cert, context);
case Cardano.CertificateType.AuthorizeCommitteeHot:
return getAuthorizeCommitteeHotCertificate(cert, context);
case Cardano.CertificateType.ResignCommitteeCold:
return getResignCommitteeColdCertificate(cert, context);
case Cardano.CertificateType.RegisterDelegateRepresentative:
return drepRegistrationCertificate(cert, context, Ledger.CertificateType.DREP_REGISTRATION);
return drepRegistrationCertificate(cert, context);
case Cardano.CertificateType.UnregisterDelegateRepresentative:
return drepRegistrationCertificate(cert, context, Ledger.CertificateType.DREP_DEREGISTRATION);
return drepRegistrationCertificate(cert, context);
case Cardano.CertificateType.UpdateDelegateRepresentative:
default:
throw new InvalidArgumentError('cert', `Certificate ${cert.__typename} not supported.`);
Expand Down
2 changes: 1 addition & 1 deletion packages/wallet/package.json
Expand Up @@ -41,7 +41,7 @@
"test:e2e": "echo 'test:e2e' command not implemented yet"
},
"devDependencies": {
"@cardano-foundation/ledgerjs-hw-app-cardano": "^6.0.0",
"@cardano-foundation/ledgerjs-hw-app-cardano": "^7.0.0",
"@cardano-ogmios/client": "5.6.0",
"@cardano-sdk/cardano-services-client": "workspace:~",
"@cardano-sdk/ogmios": "workspace:~",
Expand Down
1 change: 0 additions & 1 deletion yarn-project.nix
Expand Up @@ -383,7 +383,6 @@ cacheEntries = {
"@blockfrost/blockfrost-js@npm:5.2.0" = { filename = "@blockfrost-blockfrost-js-npm-5.2.0-5dd47056e0-285a000e95.zip"; sha512 = "285a000e95c83be4d10da903f4a2a145b4c8d01ba8a3fce37e6f1b3211e97c5d1f317d923fe81dc6b8beff5e1eeee2b68728db589f8ec46eb6c00069f306bdf2"; };
"@blockfrost/blockfrost-utils@npm:2.0.0" = { filename = "@blockfrost-blockfrost-utils-npm-2.0.0-d53fbe4bc6-51e613d14e.zip"; sha512 = "51e613d14e792a957e339bfcf0e428127e659a199a4a6a3deff41751155befb1869c3d6da29afab11a2bd431dfa4839b0e812e8c38eb89b1584661a092bf8885"; };
"@blockfrost/openapi@npm:0.1.49" = { filename = "@blockfrost-openapi-npm-0.1.49-88a1c99db2-cab0b3ec06.zip"; sha512 = "cab0b3ec0677d9a82e0cb0a6b02b5e7a4d5b0ad7ba5e6bf969142e6262eacf947f94c4d0bed397fb38e9983c20b78ed66b4b1dfab7bab7d19b38605156ee693d"; };
"@cardano-foundation/ledgerjs-hw-app-cardano@npm:6.0.0" = { filename = "@cardano-foundation-ledgerjs-hw-app-cardano-npm-6.0.0-615cff0cfb-6767792e68.zip"; sha512 = "6767792e68bd72333423eda25203b69a9686ee12602503e98037c68fc95abb74ceefc4cc1661579720fa3ecb822c4d30e0f0979fee9c8ef476668d4ee99df561"; };
"@cardano-foundation/ledgerjs-hw-app-cardano@npm:7.0.1" = { filename = "@cardano-foundation-ledgerjs-hw-app-cardano-npm-7.0.1-77358e2504-6ed9ae6804.zip"; sha512 = "6ed9ae68049a45b7175d027bb76c02f67dde10d454b35b1f34960195c90d99a867b5ec2dc2ff8dc5c54f0da9df5c2da33c6e2dcf491ab1fce284f4f74d89fd7a"; };
"@cardano-ogmios/client@npm:5.6.0" = { filename = "@cardano-ogmios-client-npm-5.6.0-e3f0ec5f2b-4d15f7a1c6.zip"; sha512 = "4d15f7a1c6178d3f83d13a8fc9af8fc054d552a5db322ff2ec952d4876f131a0d2940a4ecd9663d4497e00392743f5a04867654984ca8f466b2253cd76d09d05"; };
"@cardano-ogmios/schema@npm:5.6.0" = { filename = "@cardano-ogmios-schema-npm-5.6.0-6e5d8ece12-82d9ba119f.zip"; sha512 = "82d9ba119fd0bb54e1857bc436778f9677c99bb1ca2fe213567b05758e2fbd6bbef540c83bce53850db1f16a50c62e6522b7d792e7bd85f058a835399520b70a"; };
Expand Down
16 changes: 2 additions & 14 deletions yarn.lock
Expand Up @@ -3072,18 +3072,6 @@ __metadata:
languageName: node
linkType: hard

"@cardano-foundation/ledgerjs-hw-app-cardano@npm:^6.0.0":
version: 6.0.0
resolution: "@cardano-foundation/ledgerjs-hw-app-cardano@npm:6.0.0"
dependencies:
"@ledgerhq/hw-transport": ^6.27.10
base-x: ^3.0.5
bech32: ^1.1.4
int64-buffer: ^1.0.1
checksum: 6767792e68bd72333423eda25203b69a9686ee12602503e98037c68fc95abb74ceefc4cc1661579720fa3ecb822c4d30e0f0979fee9c8ef476668d4ee99df561
languageName: node
linkType: hard

"@cardano-foundation/ledgerjs-hw-app-cardano@npm:^7.0.0":
version: 7.0.1
resolution: "@cardano-foundation/ledgerjs-hw-app-cardano@npm:7.0.1"
Expand Down Expand Up @@ -3321,7 +3309,7 @@ __metadata:
"@babel/core": ^7.18.2
"@babel/preset-env": ^7.18.2
"@babel/preset-typescript": ^7.17.12
"@cardano-foundation/ledgerjs-hw-app-cardano": ^6.0.0
"@cardano-foundation/ledgerjs-hw-app-cardano": ^7.0.0
"@cardano-ogmios/client": 5.6.0
"@cardano-sdk/cardano-services": "workspace:~"
"@cardano-sdk/cardano-services-client": "workspace:~"
Expand Down Expand Up @@ -3751,7 +3739,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@cardano-sdk/wallet@workspace:packages/wallet"
dependencies:
"@cardano-foundation/ledgerjs-hw-app-cardano": ^6.0.0
"@cardano-foundation/ledgerjs-hw-app-cardano": ^7.0.0
"@cardano-ogmios/client": 5.6.0
"@cardano-sdk/cardano-services-client": "workspace:~"
"@cardano-sdk/core": "workspace:~"
Expand Down

0 comments on commit 3e09025

Please sign in to comment.