Skip to content

Commit b232852

Browse files
authored
Merge branch 'develop' into yushi/YOEXT-617/remove-byron
2 parents 99256b1 + 0b40cae commit b232852

File tree

10 files changed

+226
-62
lines changed

10 files changed

+226
-62
lines changed

packages/yoroi-extension/app/api/ada/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ export type CreateLedgerSignTxDataRequest = {|
297297
signRequest: HaskellShelleyTxSignRequest,
298298
network: $ReadOnly<NetworkRow>,
299299
addressingMap: string => (void | $PropertyType<Addressing, 'addressing'>),
300+
cip36: boolean,
300301
|};
301302
export type CreateLedgerSignTxDataResponse = {|
302303
ledgerSignTxPayload: SignTransactionRequest,
@@ -961,6 +962,7 @@ export default class AdaApi {
961962
byronNetworkMagic: config.ByronNetworkId,
962963
networkId: Number.parseInt(config.ChainNetworkId, 10),
963964
addressingMap: request.addressingMap,
965+
cip36: request.cip36,
964966
});
965967

966968
Logger.debug(`${nameof(AdaApi)}::${nameof(this.createLedgerSignTxData)} success: ` + stringifyData(ledgerSignTxPayload));
@@ -2382,6 +2384,8 @@ export default class AdaApi {
23822384
const usedUtxos = signRequest.senderUtxos.map(utxo => (
23832385
{ txHash: utxo.tx_hash, index: utxo.tx_index }
23842386
));
2387+
const metadata = signRequest.unsignedTx.get_auxiliary_data();
2388+
23852389
const transaction = CardanoShelleyTransaction.fromData({
23862390
txid: txId,
23872391
type: isIntraWallet ? 'self' : 'expend',
@@ -2397,8 +2401,8 @@ export default class AdaApi {
23972401
block: null,
23982402
certificates: [],
23992403
ttl: new BigNumber(String(signRequest.unsignedTx.build().ttl())),
2400-
metadata: signRequest.metadata
2401-
? Buffer.from(signRequest.metadata.to_bytes()).toString('hex')
2404+
metadata: metadata
2405+
? Buffer.from(metadata.to_bytes()).toString('hex')
24022406
: null,
24032407
withdrawals: signRequest.withdrawals().map(withdrawal => ({
24042408
address: withdrawal.address,

packages/yoroi-extension/app/api/ada/lib/cardanoCrypto/catalyst.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,74 @@ export function generateRegistration(request: {|
102102
(hashedMetadata) => request.stakePrivateKey.sign(hashedMetadata).to_hex(),
103103
);
104104
}
105+
106+
export function generateCip15RegistrationMetadata(
107+
votingPublicKey: string,
108+
stakingPublicKey: string,
109+
rewardAddress: string,
110+
nonce: number,
111+
signer: Uint8Array => string,
112+
): RustModule.WalletV4.AuxiliaryData {
113+
114+
/**
115+
* Catalyst follows a certain standard to prove the voting power
116+
* A transaction is submitted with following metadata format for the registration process
117+
* label: 61284
118+
* {
119+
* 1: "pubkey generated for catalyst app",
120+
* 2: "stake key public key",
121+
* 3: "address to receive rewards to"
122+
* 4: "slot number"
123+
* }
124+
* label: 61285
125+
* {
126+
* 1: "signature of blake2b-256 hash of the metadata signed using stakekey"
127+
* }
128+
*/
129+
130+
const registrationData = RustModule.WalletV4.encode_json_str_to_metadatum(
131+
JSON.stringify({
132+
'1': prefix0x(votingPublicKey),
133+
'2': prefix0x(stakingPublicKey),
134+
'3': prefix0x(rewardAddress),
135+
'4': nonce,
136+
}),
137+
RustModule.WalletV4.MetadataJsonSchema.BasicConversions
138+
);
139+
const generalMetadata = RustModule.WalletV4.GeneralTransactionMetadata.new();
140+
generalMetadata.insert(
141+
RustModule.WalletV4.BigNum.from_str(CatalystLabels.DATA.toString()),
142+
registrationData
143+
);
144+
145+
const hashedMetadata = blake2b(256 / 8).update(
146+
generalMetadata.to_bytes()
147+
).digest('binary');
148+
149+
generalMetadata.insert(
150+
RustModule.WalletV4.BigNum.from_str(CatalystLabels.SIG.toString()),
151+
RustModule.WalletV4.encode_json_str_to_metadatum(
152+
JSON.stringify({
153+
'1': prefix0x(signer(hashedMetadata)),
154+
}),
155+
RustModule.WalletV4.MetadataJsonSchema.BasicConversions
156+
)
157+
);
158+
159+
// This is how Ledger constructs the metadata. We must be consistent with it.
160+
const metadataList = RustModule.WalletV4.MetadataList.new();
161+
metadataList.add(
162+
RustModule.WalletV4.TransactionMetadatum.from_bytes(
163+
generalMetadata.to_bytes()
164+
)
165+
);
166+
metadataList.add(
167+
RustModule.WalletV4.TransactionMetadatum.new_list(
168+
RustModule.WalletV4.MetadataList.new()
169+
)
170+
);
171+
172+
return RustModule.WalletV4.AuxiliaryData.from_bytes(
173+
metadataList.to_bytes()
174+
);
175+
}

packages/yoroi-extension/app/api/ada/transactions/shelley/ledgerTx.js

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export async function createLedgerSignTxPayload(request: {|
4949
byronNetworkMagic: number,
5050
networkId: number,
5151
addressingMap: string => (void | $PropertyType<Addressing, 'addressing'>),
52+
cip36: boolean,
5253
|}): Promise<SignTransactionRequest> {
5354
const txBody = request.signRequest.unsignedTx.build();
5455

@@ -94,32 +95,54 @@ export async function createLedgerSignTxPayload(request: {|
9495
const { votingPublicKey, stakingKeyPath, nonce, paymentKeyPath, } =
9596
request.signRequest.ledgerNanoCatalystRegistrationTxSignData;
9697

97-
auxiliaryData = {
98-
type: TxAuxiliaryDataType.CIP36_REGISTRATION,
99-
params: {
100-
format: CIP36VoteRegistrationFormat.CIP_36,
101-
delegations: [
102-
{
103-
type: CIP36VoteDelegationType.KEY,
104-
voteKeyHex: votingPublicKey.replace(/^0x/, ''),
105-
weight: 1,
98+
if (request.cip36) {
99+
auxiliaryData = {
100+
type: TxAuxiliaryDataType.CIP36_REGISTRATION,
101+
params: {
102+
format: CIP36VoteRegistrationFormat.CIP_36,
103+
delegations: [
104+
{
105+
type: CIP36VoteDelegationType.KEY,
106+
voteKeyHex: votingPublicKey.replace(/^0x/, ''),
107+
weight: 1,
108+
},
109+
],
110+
stakingPath: stakingKeyPath,
111+
paymentDestination: {
112+
type: TxOutputDestinationType.DEVICE_OWNED,
113+
params: {
114+
type: AddressType.BASE_PAYMENT_KEY_STAKE_KEY,
115+
params: {
116+
spendingPath: paymentKeyPath,
117+
stakingPath: stakingKeyPath,
118+
},
119+
},
106120
},
107-
],
108-
stakingPath: stakingKeyPath,
109-
paymentDestination: {
110-
type: TxOutputDestinationType.DEVICE_OWNED,
111-
params: {
112-
type: AddressType.BASE_PAYMENT_KEY_STAKE_KEY,
121+
nonce,
122+
votingPurpose: 0,
123+
}
124+
};
125+
} else {
126+
auxiliaryData = {
127+
type: TxAuxiliaryDataType.CIP36_REGISTRATION,
128+
params: {
129+
format: CIP36VoteRegistrationFormat.CIP_15,
130+
voteKeyHex: votingPublicKey.replace(/^0x/, ''),
131+
stakingPath: stakingKeyPath,
132+
paymentDestination: {
133+
type: TxOutputDestinationType.DEVICE_OWNED,
113134
params: {
114-
spendingPath: paymentKeyPath,
115-
stakingPath: stakingKeyPath,
135+
type: AddressType.BASE_PAYMENT_KEY_STAKE_KEY,
136+
params: {
137+
spendingPath: paymentKeyPath,
138+
stakingPath: stakingKeyPath,
139+
},
116140
},
117141
},
118-
},
119-
nonce,
120-
votingPurpose: 0,
121-
}
122-
};
142+
nonce,
143+
}
144+
};
145+
}
123146
} else if (request.signRequest.metadata != null) {
124147
auxiliaryData = {
125148
type: TxAuxiliaryDataType.ARBITRARY_HASH,

packages/yoroi-extension/app/api/ada/transactions/shelley/ledgerTx.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ test('Create Ledger transaction', async () => {
351351
}
352352
return undefined;
353353
},
354+
cip36: true,
354355
});
355356

356357
expect(response).toStrictEqual(({

packages/yoroi-extension/app/api/ada/transactions/shelley/transactions.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,9 +1044,7 @@ function newAdaUnsignedTxFromUtxoForConnector(
10441044
txBuilder.set_collateral(collateralBuilder);
10451045
// script data hash
10461046
txBuilder.calc_script_data_hash(
1047-
protocolParams.networkId > 0 ?
1048-
RustModule.WalletV4.TxBuilderConstants.plutus_vasil_cost_models()
1049-
: RustModule.WalletV4.TxBuilderConstants.plutus_default_cost_models(),
1047+
RustModule.WalletV4.TxBuilderConstants.plutus_default_cost_models(),
10501048
);
10511049
}
10521050

packages/yoroi-extension/app/stores/ada/send/LedgerSendStore.js

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ import type {
4545
import { genAddressingLookup } from '../../stateless/addressStores';
4646
import type { ActionsMap } from '../../../actions/index';
4747
import type { StoresMap } from '../../index';
48-
import { generateRegistrationMetadata } from '../../../api/ada/lib/cardanoCrypto/catalyst';
48+
import {
49+
generateRegistrationMetadata,
50+
generateCip15RegistrationMetadata,
51+
} from '../../../api/ada/lib/cardanoCrypto/catalyst';
4952

5053
/** Note: Handles Ledger Signing */
5154
export default class LedgerSendStore extends Store<StoresMap, ActionsMap> {
@@ -207,18 +210,29 @@ export default class LedgerSendStore extends Store<StoresMap, ActionsMap> {
207210
locale: this.stores.profile.currentLocale,
208211
});
209212
213+
let cip36: boolean = false;
214+
if (request.signRequest.ledgerNanoCatalystRegistrationTxSignData) {
215+
const getVersionResponse = await ledgerConnect.getVersion({
216+
serial: request.expectedSerial,
217+
dontCloseTab: true,
218+
});
219+
cip36 = getVersionResponse.compatibility.supportsCIP36Vote === true;
220+
}
221+
210222
const network = request.publicDeriver.getParent().getNetworkInfo();
211223
212224
const { ledgerSignTxPayload } = await this.api.ada.createLedgerSignTxData({
213225
signRequest: request.signRequest,
214226
network,
215227
addressingMap: request.addressingMap,
228+
cip36,
216229
});
217230
218231
const ledgerSignTxResp: LedgerSignTxResponse =
219232
await ledgerConnect.signTransaction({
220233
serial: request.expectedSerial,
221234
params: ledgerSignTxPayload,
235+
useOpenTab: true,
222236
});
223237
224238
// There is no need of ledgerConnect after this line.
@@ -247,15 +261,27 @@ export default class LedgerSendStore extends Store<StoresMap, ActionsMap> {
247261
const { cip36VoteRegistrationSignatureHex } =
248262
ledgerSignTxResp.auxiliaryDataSupplement;
249263
250-
metadata = generateRegistrationMetadata(
251-
votingPublicKey,
252-
stakingKey,
253-
paymentAddress,
254-
nonce,
255-
(_hashedMetadata) => {
256-
return cip36VoteRegistrationSignatureHex;
257-
},
258-
);
264+
if (cip36) {
265+
metadata = generateRegistrationMetadata(
266+
votingPublicKey,
267+
stakingKey,
268+
paymentAddress,
269+
nonce,
270+
(_hashedMetadata) => {
271+
return cip36VoteRegistrationSignatureHex;
272+
},
273+
);
274+
} else {
275+
metadata = generateCip15RegistrationMetadata(
276+
votingPublicKey,
277+
stakingKey,
278+
paymentAddress,
279+
nonce,
280+
(_hashedMetadata) => {
281+
return cip36VoteRegistrationSignatureHex;
282+
},
283+
);
284+
}
259285
// We can verify that
260286
// Buffer.from(
261287
// blake2b(256 / 8).update(metadata.to_bytes()).digest('binary')

packages/yoroi-extension/app/utils/hwConnectHandler.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type ShowAddressRequestWrapper = {|
2929

3030
export class LedgerConnect {
3131
locale: string;
32+
tabId: ?number;
3233

3334
constructor(params: {| locale: string |}) {
3435
this.locale = params.locale;
@@ -59,11 +60,14 @@ export class LedgerConnect {
5960
signTransaction: {|
6061
serial: ?string,
6162
params: SignTransactionRequest,
63+
useOpenTab?: boolean,
6264
|} => Promise<SignTransactionResponse> = (request) => {
6365
return this._requestLedger(
6466
OPERATION_NAME.SIGN_TX,
6567
request.params,
6668
request.serial,
69+
false,
70+
request.useOpenTab === true,
6771
);
6872
}
6973

@@ -78,12 +82,34 @@ export class LedgerConnect {
7882
);
7983
}
8084

85+
getVersion: {|
86+
serial: ?string,
87+
dontCloseTab?: boolean,
88+
|} => Promise<GetVersionResponse> = (request) => {
89+
return this._requestLedger(
90+
OPERATION_NAME.GET_LEDGER_VERSION,
91+
undefined,
92+
request.serial,
93+
true,
94+
);
95+
}
96+
8197
async _requestLedger(
8298
action: string,
8399
params: any,
84100
serial: ?string,
101+
dontCloseTab?: boolean = false,
102+
useOpenTab?: boolean = false,
85103
): any {
86-
const tabId = await this._createLedgerTab();
104+
let tabId;
105+
if (useOpenTab && this.tabId != null) {
106+
tabId = this.tabId;
107+
} else {
108+
tabId = await this._createLedgerTab();
109+
if (dontCloseTab) {
110+
this.tabId = tabId;
111+
}
112+
}
87113

88114
return new Promise((resolve, reject) => {
89115
chrome.tabs.sendMessage(

0 commit comments

Comments
 (0)