From 694ba67596ecf2b7c28736ce63b6f624e00d809b Mon Sep 17 00:00:00 2001
From: Mateusz Jasiuk
Date: Wed, 8 Jan 2025 14:15:37 +0100
Subject: [PATCH] feat: unshielding working
---
.../src/Approvals/ConfirmSignLedgerTx.tsx | 50 +++++++++++++-----
.../src/background/approvals/handler.ts | 14 +++++
.../src/background/approvals/init.ts | 2 +
.../src/background/approvals/messages.ts | 33 +++++++++++-
.../src/background/approvals/service.ts | 52 ++++++++++++++-----
apps/namadillo/public/config.toml | 2 +-
apps/namadillo/src/atoms/transfer/services.ts | 13 ++++-
apps/namadillo/src/workers/MaspTxWorker.ts | 2 +-
packages/shared/lib/src/sdk/mod.rs | 26 ++++++----
9 files changed, 155 insertions(+), 39 deletions(-)
diff --git a/apps/extension/src/Approvals/ConfirmSignLedgerTx.tsx b/apps/extension/src/Approvals/ConfirmSignLedgerTx.tsx
index 96cd2be4d2..e98003c097 100644
--- a/apps/extension/src/Approvals/ConfirmSignLedgerTx.tsx
+++ b/apps/extension/src/Approvals/ConfirmSignLedgerTx.tsx
@@ -2,15 +2,16 @@ import clsx from "clsx";
import { ReactNode, useCallback, useEffect, useState } from "react";
import { ActionButton, Stack } from "@namada/components";
-import { Ledger, makeBip44Path } from "@namada/sdk/web";
+import { Ledger, makeBip44Path, makeSaplingPath } from "@namada/sdk/web";
import { LedgerError, ResponseSign } from "@zondax/ledger-namada";
-import { fromBase64 } from "@cosmjs/encoding";
+import { fromBase64, toBase64 } from "@cosmjs/encoding";
import { chains } from "@namada/chains";
import { PageHeader } from "App/Common";
import { ApprovalDetails, Status } from "Approvals/Approvals";
import {
QueryPendingTxBytesMsg,
+ ReplaceMaspSignatureMsg,
SubmitApprovedSignLedgerTxMsg,
} from "background/approvals";
import { QueryAccountDetailsMsg } from "background/keyring";
@@ -75,15 +76,27 @@ export const ConfirmSignLedgerTx: React.FC = ({ details }) => {
const signMaspTx = async (
ledger: Ledger,
bytes: Uint8Array,
- _path: string
+ path: string
): Promise<{ sbar: Uint8Array; rbar: Uint8Array }> => {
- const _response = await ledger.namadaApp.signMaspSpends(
- // TODO:
- "m/32'/877'/0'",
+ const signMaspSpendsResponse = await ledger.namadaApp.signMaspSpends(
+ path,
Buffer.from(bytes)
);
- // TODO
- return await ledger.namadaApp.getSpendSignature();
+
+ if (signMaspSpendsResponse.returnCode !== LedgerError.NoErrors) {
+ throw new Error(
+ `Signing masp spends error encountered: ${signMaspSpendsResponse.errorMessage}`
+ );
+ }
+
+ const spendSignatureResponse = await ledger.namadaApp.getSpendSignature();
+ if (spendSignatureResponse.returnCode !== LedgerError.NoErrors) {
+ throw new Error(
+ `Getting spends signature error encountered: ${signMaspSpendsResponse.errorMessage}`
+ );
+ }
+
+ return spendSignatureResponse;
};
const signLedgerTx = async (
@@ -150,6 +163,9 @@ export const ConfirmSignLedgerTx: React.FC = ({ details }) => {
index: accountDetails.path.index || 0,
};
const bip44Path = makeBip44Path(chains.namada.bip44.coinType, path);
+ const zip32Path = makeSaplingPath(chains.namada.bip44.coinType, {
+ account: path.account,
+ });
const pendingTxs = await requester.sendMessage(
Ports.Background,
new QueryPendingTxBytesMsg(msgId)
@@ -162,7 +178,7 @@ export const ConfirmSignLedgerTx: React.FC = ({ details }) => {
}
const signatures: ResponseSign[] = [];
- const maspSignatures: number[][] = [];
+ const maspSignatures: string[] = [];
let txIndex = 0;
const txCount = pendingTxs.length;
@@ -182,13 +198,23 @@ export const ConfirmSignLedgerTx: React.FC = ({ details }) => {
);
}
- const asd = await signMaspTx(ledger, fromBase64(tx), bip44Path);
- const maspSignature = [...asd.rbar, ...asd.sbar];
+ const { sbar, rbar } = await signMaspTx(
+ ledger,
+ fromBase64(tx),
+ zip32Path
+ );
+ const maspSignature = toBase64(new Uint8Array([...rbar, ...sbar]));
maspSignatures.push(maspSignature);
+ const txWithMaspSection = await requester.sendMessage(
+ Ports.Background,
+ new ReplaceMaspSignatureMsg(msgId, maspSignature, txIndex)
+ );
+ console.log("txWithMaspSection", txWithMaspSection);
+
const signature = await signLedgerTx(
ledger,
- fromBase64(tx),
+ fromBase64(txWithMaspSection),
bip44Path
);
signatures.push(signature);
diff --git a/apps/extension/src/background/approvals/handler.ts b/apps/extension/src/background/approvals/handler.ts
index 65f880333e..5e38c02ce4 100644
--- a/apps/extension/src/background/approvals/handler.ts
+++ b/apps/extension/src/background/approvals/handler.ts
@@ -16,6 +16,7 @@ import {
QueryTxDetailsMsg,
RejectSignArbitraryMsg,
RejectSignTxMsg,
+ ReplaceMaspSignatureMsg,
RevokeConnectionMsg,
SubmitApprovedSignArbitraryMsg,
SubmitApprovedSignLedgerTxMsg,
@@ -113,6 +114,11 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => {
env,
msg as SubmitApprovedSignLedgerTxMsg
);
+ case ReplaceMaspSignatureMsg:
+ return handleReplaceMaspSignatureMsg(service)(
+ env,
+ msg as ReplaceMaspSignatureMsg
+ );
default:
throw new Error("Unknown msg type");
@@ -287,6 +293,14 @@ const handleSubmitApprovedSignLedgerTxMsg: (
};
};
+const handleReplaceMaspSignatureMsg: (
+ service: ApprovalsService
+) => InternalHandler = (service) => {
+ return async (_, { msgId, signature, txIndex }) => {
+ return await service.replaceMaspSignature(msgId, signature, txIndex);
+ };
+};
+
const handleCheckIsApprovedSite: (
service: ApprovalsService
) => InternalHandler = (service) => {
diff --git a/apps/extension/src/background/approvals/init.ts b/apps/extension/src/background/approvals/init.ts
index 37e95732a1..bb2976235c 100644
--- a/apps/extension/src/background/approvals/init.ts
+++ b/apps/extension/src/background/approvals/init.ts
@@ -16,6 +16,7 @@ import {
QueryTxDetailsMsg,
RejectSignArbitraryMsg,
RejectSignTxMsg,
+ ReplaceMaspSignatureMsg,
RevokeConnectionMsg,
SubmitApprovedSignArbitraryMsg,
SubmitApprovedSignLedgerTxMsg,
@@ -36,6 +37,7 @@ export function init(router: Router, service: ApprovalsService): void {
router.registerMessage(SubmitApprovedSignTxMsg);
router.registerMessage(SubmitApprovedSignArbitraryMsg);
router.registerMessage(SubmitApprovedSignLedgerTxMsg);
+ router.registerMessage(ReplaceMaspSignatureMsg);
router.registerMessage(IsConnectionApprovedMsg);
router.registerMessage(ApproveConnectInterfaceMsg);
router.registerMessage(ConnectInterfaceResponseMsg);
diff --git a/apps/extension/src/background/approvals/messages.ts b/apps/extension/src/background/approvals/messages.ts
index 80dbe70f69..bbb1ee6dcd 100644
--- a/apps/extension/src/background/approvals/messages.ts
+++ b/apps/extension/src/background/approvals/messages.ts
@@ -10,6 +10,7 @@ export enum MessageType {
SubmitApprovedSignTx = "submit-approved-sign-tx",
SubmitApprovedSignArbitrary = "submit-approved-sign-arbitrary",
SubmitApprovedSignLedgerTx = "submit-approved-sign-ledger-tx",
+ ReplaceMaspSignature = "replace-masp-signature",
RejectSignArbitrary = "reject-sign-arbitrary",
ConnectInterfaceResponse = "connect-interface-response",
DisconnectInterfaceResponse = "disconnect-interface-response",
@@ -54,7 +55,8 @@ export class SubmitApprovedSignLedgerTxMsg extends Message {
constructor(
public readonly msgId: string,
public readonly responseSign: ResponseSign[],
- public readonly maspSignatures: number[][]
+ //base64 encoded masp signatures
+ public readonly maspSignatures: string[]
) {
super();
}
@@ -72,6 +74,35 @@ export class SubmitApprovedSignLedgerTxMsg extends Message {
}
}
+// returns base64 encoded tx
+export class ReplaceMaspSignatureMsg extends Message {
+ public static type(): MessageType {
+ return MessageType.ReplaceMaspSignature;
+ }
+
+ constructor(
+ public readonly msgId: string,
+ // base64 encoded
+ public readonly signature: string,
+ // pending tx index
+ public readonly txIndex: number
+ ) {
+ super();
+ }
+
+ validate(): void {
+ validateProps(this, ["msgId", "signature", "txIndex"]);
+ }
+
+ route(): string {
+ return ROUTE;
+ }
+
+ type(): string {
+ return ReplaceMaspSignatureMsg.type();
+ }
+}
+
export class RejectSignTxMsg extends Message {
public static type(): MessageType {
return MessageType.RejectSignTx;
diff --git a/apps/extension/src/background/approvals/service.ts b/apps/extension/src/background/approvals/service.ts
index c24efb074b..678b646648 100644
--- a/apps/extension/src/background/approvals/service.ts
+++ b/apps/extension/src/background/approvals/service.ts
@@ -1,4 +1,4 @@
-import { toBase64 } from "@cosmjs/encoding";
+import { fromBase64, toBase64 } from "@cosmjs/encoding";
import { v4 as uuid } from "uuid";
import browser, { Windows } from "webextension-polyfill";
@@ -137,7 +137,7 @@ export class ApprovalsService {
popupTabId: number,
msgId: string,
responseSign: ResponseSign[],
- maspSignatures: number[][]
+ maspSignatures: string[]
): Promise {
const pendingTx = await this.txStore.get(msgId);
const resolvers = this.getResolver(popupTabId);
@@ -152,19 +152,22 @@ export class ApprovalsService {
const { tx } = this.sdkService.getSdk();
- console.log("maspSignatures", maspSignatures);
try {
- const signedTxs = pendingTx.txs.map(({ bytes, signingData }, i) => {
- const sd = signingData.map((sd) =>
- new Message().encode(new SigningDataMsgValue(sd))
+ const signedTxs = pendingTx.txs.map((pendingTx, i) => {
+ const signingData = pendingTx.signingData.map((signingData) =>
+ new Message().encode(new SigningDataMsgValue(signingData))
+ );
+ const maspSignature = fromBase64(maspSignatures[i]);
+ // TODO: consider improving this, explanation below:
+ // Because we read tx from the store we have to append masp signatures twice
+ // First time before ledger computes tx wrapper signature and second time now to submit proper tx
+ const txWithMasp = tx.appendMaspSignature(
+ pendingTx.bytes,
+ signingData,
+ maspSignature
);
- const wwww = new Uint8Array(maspSignatures[i]);
- console.log("sd", sd, maspSignatures[i], i);
- const asd = tx.appendMaspSignature(bytes, sd, wwww);
- console.log("asd", asd);
- // return tx.appendSignature(asd, responseSign[i]);
- return asd;
+ return tx.appendSignature(txWithMasp, responseSign[i]);
});
resolvers.resolve(signedTxs);
} catch (e) {
@@ -174,6 +177,31 @@ export class ApprovalsService {
await this.clearPendingSignature(msgId);
}
+ async replaceMaspSignature(
+ msgId: string,
+ signature: string,
+ txIndex: number
+ ): Promise {
+ const pendingTx = (await this.txStore.get(msgId))?.txs.at(txIndex);
+
+ if (!pendingTx) {
+ throw new Error(ApprovalErrors.TransactionDataNotFound(msgId));
+ }
+
+ const { tx } = this.sdkService.getSdk();
+
+ const signingData = pendingTx.signingData.map((signingData) =>
+ new Message().encode(new SigningDataMsgValue(signingData))
+ );
+ const txWithMasp = tx.appendMaspSignature(
+ pendingTx.bytes,
+ signingData,
+ fromBase64(signature)
+ );
+
+ return toBase64(txWithMasp);
+ }
+
async submitSignArbitrary(
popupTabId: number,
msgId: string,
diff --git a/apps/namadillo/public/config.toml b/apps/namadillo/public/config.toml
index 29d5b71031..7bd0c7210c 100644
--- a/apps/namadillo/public/config.toml
+++ b/apps/namadillo/public/config.toml
@@ -2,4 +2,4 @@
#indexer_url = ""
#rpc_url = ""
#masp_indexer_url = ""
-#localnet_enabled = false
+localnet_enabled = true
diff --git a/apps/namadillo/src/atoms/transfer/services.ts b/apps/namadillo/src/atoms/transfer/services.ts
index 7e6e16471b..c9e3408a13 100644
--- a/apps/namadillo/src/atoms/transfer/services.ts
+++ b/apps/namadillo/src/atoms/transfer/services.ts
@@ -188,22 +188,31 @@ export const createUnshieldingTransferTx = async (
const token = props[0]?.data[0]?.token;
const amount = props[0]?.data[0]?.amount;
+ const sdk = await getSdkInstance();
+ const ledger = await sdk.initLedger();
+
+ const bparams = await ledger.getBparams();
+ ledger.closeTransport();
+ console.log("bparams closed", bparams);
+
return await workerBuildTxPair({
rpcUrl,
token,
- signerAddress: disposableSigner.address,
+ signerAddress: account.address,
+ // signerAddress: disposableSigner.address,
buildTxFn: async (workerLink) => {
const msgValue = new UnshieldingTransferMsgValue({
source,
gasSpendingKey: source,
data: [{ target: destination, token, amount }],
+ bparams,
});
const msg: Unshield = {
type: "unshield",
payload: {
account: {
...account,
- publicKey: disposableSigner.publicKey,
+ // publicKey: disposableSigner.publicKey,
},
gasConfig,
props: [msgValue],
diff --git a/apps/namadillo/src/workers/MaspTxWorker.ts b/apps/namadillo/src/workers/MaspTxWorker.ts
index 644da1a446..c5f4562fb7 100644
--- a/apps/namadillo/src/workers/MaspTxWorker.ts
+++ b/apps/namadillo/src/workers/MaspTxWorker.ts
@@ -115,7 +115,6 @@ async function unshield(
await sdk.masp.loadMaspParams("", chain.chainId);
- console.log("Unshielding props", unshieldingProps);
const encodedTxData = await buildTx(
sdk,
account,
@@ -125,6 +124,7 @@ async function unshield(
sdk.tx.buildUnshieldingTransfer,
true
);
+ console.log("encodedTxData", encodedTxData);
return encodedTxData;
}
diff --git a/packages/shared/lib/src/sdk/mod.rs b/packages/shared/lib/src/sdk/mod.rs
index 117c54cc06..4f92f1ea4f 100644
--- a/packages/shared/lib/src/sdk/mod.rs
+++ b/packages/shared/lib/src/sdk/mod.rs
@@ -596,22 +596,28 @@ impl Sdk {
(tx, masp_signing_data)
}
BuildParams::StoredBuildParams(mut bparams) => {
+ web_sys::console::log_1(&"StoredBuildParams".into());
let tx = build_unshielding_transfer(&self.namada, &mut args, &mut bparams).await?;
let masp_signing_data = MaspSigningData::new(bparams, xfvks);
(tx, masp_signing_data)
}
};
-
- if let Some(shielded_hash) = signing_data.shielded_hash {
- web_sys::console::log_1(
- &format!(
- "tx: {:?}",
- borsh::to_vec(tx.get_masp_section(&shielded_hash).unwrap())
- )
- .into(),
- );
- }
+ web_sys::console::log_1(&format!("signing_data owner: {:?}", signing_data.owner).into());
+ web_sys::console::log_1(
+ &format!("signing_data public_keys: {:?}", signing_data.public_keys).into(),
+ );
+ web_sys::console::log_1(&format!("signing_data fee: {:?}", signing_data.fee_payer).into());
+
+ // if let Some(shielded_hash) = signing_data.shielded_hash {
+ // web_sys::console::log_1(
+ // &format!(
+ // "tx: {:?}",
+ // borsh::to_vec(tx.get_masp_section(&shielded_hash).unwrap())
+ // )
+ // .into(),
+ // );
+ // }
self.serialize_tx_result(tx, wrapper_tx_msg, signing_data, Some(masp_signing_data))
}