Skip to content

Commit

Permalink
Merge pull request #3296 from Emurgo/feat/YOEXT-799/cip95-signTx
Browse files Browse the repository at this point in the history
connector signTx witnesses CIP95 certificates and tx fields
  • Loading branch information
vsubhuman authored Sep 26, 2023
2 parents 74736f8 + 9c5b640 commit 5cd1dd0
Showing 1 changed file with 126 additions and 2 deletions.
128 changes: 126 additions & 2 deletions packages/yoroi-extension/chrome/extension/connector/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,12 @@ export async function connectorGetUnusedAddresses(wallet: PublicDeriver<>): Prom
export async function connectorGetDRepKey(
wallet: PublicDeriver<>,
): Promise<string> {
return (await _getDRepKeyAndAddressing(wallet))[0].to_hex();
}

async function _getDRepKeyAndAddressing(
wallet: PublicDeriver<>,
): Promise<[RustModule.WalletV4.PublicKey, Addressing]> {
const withPubKey = asGetPublicKey(wallet);
if (withPubKey == null) {
throw new Error('Unable to get public key from the wallet');
Expand All @@ -491,7 +497,7 @@ export async function connectorGetDRepKey(
const publicKey = RustModule.WalletV4.Bip32PublicKey.from_bytes(
Buffer.from(publicKeyResp.Hash, 'hex')
);
const dRepKey = derivePublicByAddressing({
const addressing = {
addressing: {
path: [
WalletTypePurpose.CIP1852,
Expand All @@ -502,12 +508,16 @@ export async function connectorGetDRepKey(
],
startLevel: Bip44DerivationLevels.PURPOSE.level,
},
};

const dRepKey = derivePublicByAddressing({
...addressing,
startingFrom: {
level: withLevels.getParent().getPublicDeriverLevel(),
key: publicKey,
},
}).to_raw_key();
return dRepKey.to_hex();
return [dRepKey, addressing];
}

export async function connectorGetStakeKey(
Expand Down Expand Up @@ -797,6 +807,109 @@ function getTxRequiredSigningKeys(
return set;
}

function getCip95RequiredSignKeys(
txBody: RustModule.WalletV4.TransactionBody,
): Set<string> {
const result: Set<string> = new Set();

const certs = txBody.certs();
if (certs) {
for (let i = 0; i < certs.len(); i++) {
const cert = certs.get(i);
if (!cert) {
throw new Error('unexpectedly missing certificate');
}
const stakeDeregistration = cert.as_stake_deregistration();
if (stakeDeregistration) {
const keyHash = stakeDeregistration.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const stakeDelegation = cert.as_stake_delegation();
if (stakeDelegation) {
const keyHash = stakeDelegation.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const voteDelegation = cert.as_vote_delegation();
if (voteDelegation) {
const keyHash = voteDelegation.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const stakeVoteDelegation = cert.as_stake_and_vote_delegation();
if (stakeVoteDelegation) {
const keyHash = stakeVoteDelegation.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const stakeRegDelegation = cert.as_stake_registration_and_delegation();
if (stakeRegDelegation) {
const keyHash = stakeRegDelegation.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const voteRegDelegation = cert.as_vote_registration_and_delegation();
if (voteRegDelegation) {
const keyHash = voteRegDelegation.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const stakeRegVoteDeletion = cert.as_stake_vote_registration_and_delegation();
if (stakeRegVoteDeletion) {
const keyHash = stakeRegVoteDeletion.stake_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const unregDrep = cert.as_drep_deregistration();
if (unregDrep) {
const keyHash = unregDrep.voting_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
const updateDrep = cert.as_drep_update();
if (updateDrep) {
const keyHash = updateDrep.voting_credential().to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
continue;
}
}
}

const voters = txBody.voting_procedures()?.get_voters();
if (voters) {
for (let i = 0; i < voters.len(); i++) {
const voter = voters.get(i);
if (!voter) {
throw new Error('unexpectedly missing voter');
}
const keyHash = voter.to_drep_cred()?.to_keyhash();
if (keyHash) {
result.add(keyHash.to_hex());
}
}
}
return result;
}

/**
* Returns HEX of a serialised witness set
*/
Expand Down Expand Up @@ -853,9 +966,11 @@ async function __connectorSignCardanoTx(

const requiredTxSignKeys = getTxRequiredSigningKeys(txBody);
const requiredScriptSignKeys = getScriptRequiredSigningKeys(witnessSet);
const requiredCip95SignKeys = getCip95RequiredSignKeys(txBody);
const totalAdditionalRequiredSignKeys = new Set<string>([
...requiredTxSignKeys,
...requiredScriptSignKeys,
...requiredCip95SignKeys,
]);

console.log('totalAdditionalRequiredSignKeys', [...totalAdditionalRequiredSignKeys]);
Expand Down Expand Up @@ -931,6 +1046,15 @@ async function __connectorSignCardanoTx(
otherRequiredSigners.push({ address, addressing });
}
}
const [ drepKey, addressing ] = await _getDRepKeyAndAddressing(publicDeriver);
const drepCred = drepKey.hash().to_hex();
if (totalAdditionalRequiredSignKeys.has(drepCred)) {
const address = RustModule.WalletV4.RewardAddress.new(
0, // strictly speaking should use `ChainNetworkId` but doesn't matter
RustModule.WalletV4.Credential.from_keyhash(drepKey.hash()),
).to_address().to_hex();
otherRequiredSigners.push({ address, ...addressing });
}
console.log('otherRequiredSigners', [...otherRequiredSigners]);
}

Expand Down

0 comments on commit 5cd1dd0

Please sign in to comment.